diff --git a/annotation-client/src/main/java/eu/europeana/annotation/client/config/ClientConfiguration.java b/annotation-client/src/main/java/eu/europeana/annotation/client/config/ClientConfiguration.java index 3b9d85702..6f2460666 100644 --- a/annotation-client/src/main/java/eu/europeana/annotation/client/config/ClientConfiguration.java +++ b/annotation-client/src/main/java/eu/europeana/annotation/client/config/ClientConfiguration.java @@ -8,18 +8,18 @@ public class ClientConfiguration { protected static final String ANNOTATION_CLIENT_PROPERTIES_FILE = "/annotation-client.properties"; - protected static final String PROP_ANNOTATION_API_KEY = "annotation.api.key"; - protected static final String PROP_ANNOTATION_SERVICE_BASE_URI = "annotation.service.uri"; - protected static final String PROP_ANNOTATION_ID_BASE_URI = "annotation.id.baseUrl"; - protected static final String PROP_ANNOTATION_ITEM_DATA_ENDPOINT = "annotation.item.data.endpoint"; - protected static final String PROP_ANNOTATION_CLIENT_API_ENDPOINT = "annotation.client.api.endpoint"; - - protected static final String PROP_AUTHORIZATION_HEADER_NAME = "annotation.header.name"; - protected static final String PROP_REGULAR_AUTHORIZATION_HEADER_VALUE = "annotation.regular.authorization.value"; - protected static final String PROP_ADMIN_ANNOTATION_HEADER_VALUE = "annotation.admin.authorization.value"; - - protected static final String PROP_OAUTH_SERVICE_URI = "oauth.service.uri"; - protected static final String PROP_OAUTH_REQUEST_PARAMS_PREFIX = "oauth.token.request.params."; + public static final String PROP_ANNOTATION_API_KEY = "annotation.api.key"; + public static final String PROP_ANNOTATION_SERVICE_BASE_URI = "annotation.service.uri"; + public static final String PROP_ANNOTATION_ID_BASE_URI = "annotation.id.baseUrl"; + public static final String PROP_ANNOTATION_ITEM_DATA_ENDPOINT = "annotation.item.data.endpoint"; + public static final String PROP_ANNOTATION_CLIENT_API_ENDPOINT = "annotation.client.api.endpoint"; + + public static final String PROP_AUTHORIZATION_HEADER_NAME = "annotation.header.name"; + public static final String PROP_REGULAR_AUTHORIZATION_HEADER_VALUE = "annotation.regular.authorization.value"; + public static final String PROP_ADMIN_ANNOTATION_HEADER_VALUE = "annotation.admin.authorization.value"; + + public static final String PROP_OAUTH_SERVICE_URI = "oauth.service.uri"; + public static final String PROP_OAUTH_REQUEST_PARAMS_PREFIX = "oauth.token.request.params."; private static Properties properties = null; @@ -44,6 +44,10 @@ public static synchronized ClientConfiguration getInstance() { return singleton; } + public ClientConfiguration(Properties properties) { + this.properties = properties; + } + /** * Laizy loading of configuration properties */ diff --git a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/WebAnnotationProtocolTest.java b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/WebAnnotationProtocolTest.java index b03a71416..f5856885a 100644 --- a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/WebAnnotationProtocolTest.java +++ b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/WebAnnotationProtocolTest.java @@ -3,12 +3,15 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.IOException; import java.lang.reflect.InvocationTargetException; + import org.apache.stanbol.commons.exception.JsonParseException; import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; + import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.vocabulary.WebAnnotationFields; @@ -147,7 +150,7 @@ public void updateAnnotation() throws JsonParseException, IOException { assertEquals( HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); assertEquals(TAG_STANDARD_TEST_VALUE_BODY, updatedAnnotation.getBody().getValue()); - assertEquals(get_TAG_STANDARD_TEST_VALUE_TARGET(), updatedAnnotation.getTarget().getHttpUri()); + assertEquals(get_TAG_STANDARD_TEST_VALUE_TARGET(), updatedAnnotation.getTarget().get(0).getHttpUri()); //TODO: search annotation in solr and verify body and target values. } diff --git a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/WebNewAnnotationProtocolTest.java b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/WebNewAnnotationProtocolTest.java index 7d8c121d6..3ea5f762c 100644 --- a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/WebNewAnnotationProtocolTest.java +++ b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/WebNewAnnotationProtocolTest.java @@ -2,13 +2,16 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; + import java.io.IOException; import java.lang.reflect.InvocationTargetException; + import org.apache.stanbol.commons.exception.JsonParseException; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; + import eu.europeana.annotation.definitions.model.Annotation; @@ -69,7 +72,7 @@ public void updateAnnotation() throws JsonParseException, IOException { assertEquals( HttpStatus.CREATED, response.getStatusCode()); assertNotNull(response.getBody()); assertEquals(TAG_STANDARD_TEST_VALUE_BODY, updatedAnnotation.getBody().getValue()); - assertEquals(get_TAG_STANDARD_TEST_VALUE_TARGET(), updatedAnnotation.getTarget().getHttpUri()); + assertEquals(get_TAG_STANDARD_TEST_VALUE_TARGET(), updatedAnnotation.getTarget().get(0).getHttpUri()); } @Test diff --git a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/describing/DescribingWebResourceTest.java b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/describing/DescribingWebResourceTest.java index 432acafe6..68de660fd 100644 --- a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/describing/DescribingWebResourceTest.java +++ b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/describing/DescribingWebResourceTest.java @@ -41,7 +41,7 @@ public void createFullTextResource() throws IOException, JsonParseException, Ill Annotation storedAnno = getApiProtocolClient().parseResponseBody(response); assertTrue(storedAnno.getMotivation().equals(MotivationTypes.DESCRIBING.name().toLowerCase())); - assertTrue(storedAnno.getTarget().getSource() != null); + assertTrue(storedAnno.getTarget().get(0).getSource() != null); assertEquals(storedAnno.getBody().getInternalType(), BodyInternalTypes.TEXT.name()); removeAnnotation(storedAnno.getIdentifier()); diff --git a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/AnnotationSearchFieldsTest.java b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/AnnotationSearchFieldsTest.java index 212638065..866fbb568 100644 --- a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/AnnotationSearchFieldsTest.java +++ b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/AnnotationSearchFieldsTest.java @@ -3,10 +3,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.IOException; import java.lang.reflect.InvocationTargetException; + import org.apache.stanbol.commons.exception.JsonParseException; import org.junit.jupiter.api.Test; + import eu.europeana.annotation.client.config.ClientConfiguration; import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.body.GraphBody; @@ -65,7 +68,7 @@ public void createGeoTag() throws IOException, JsonParseException, IllegalAccess assertTrue(placeBody.getLatitude().equals("48.853415")); assertNotNull(placeBody.getLongitude()); assertTrue(placeBody.getLongitude().equals("-102.348800")); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri().equals(ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/09102/_UEDIN_214")); } @@ -97,7 +100,7 @@ public void createTag() throws IOException, JsonParseException, IllegalAccessExc TagBody tagBody = ((TagBody) retrievedAnno.getBody()); assertNotNull(tagBody.getValue()); assertTrue(tagBody.getValue().equals("trombone")); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri().equals(ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/000002/_UEDIN_214")); } @@ -125,7 +128,7 @@ public void createTagText() throws IOException, JsonParseException, IllegalAcces TextBody textBody = ((TextBody) retrievedAnno.getBody()); assertNotNull(textBody.getValue()); assertTrue(textBody.getValue().equals("... this is the textual description of the item ...")); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getSource()); assertTrue(target.getSource().equals("http://www.europeana1914-1918.eu/attachments/2020601/20841.235882.full.jpg")); assertNotNull(target.getScope()); @@ -148,7 +151,7 @@ public void createLink() throws IOException, JsonParseException, IllegalAccessEx // validate fields assertTrue(retrievedAnno.getMotivation().equals(MotivationTypes.LINKING.name().toLowerCase())); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getValues()); assertTrue(target.getValues().contains(ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/2020601/https___1914_1918_europeana_eu_contributions_19584")); } @@ -169,7 +172,7 @@ public void createSemanticLink() throws IOException, JsonParseException, Illegal // validate fields assertTrue(retrievedAnno.getMotivation().equals(MotivationTypes.LINKING.name().toLowerCase())); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri().equals(ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/2048410/item_I5DUPVW2Q5HT2OQFSVXV7VYODA5P32P6")); } @@ -198,7 +201,7 @@ public void createGraph() throws IOException, JsonParseException, IllegalAccessE assertTrue(graphBody.getNode().getHttpUri().equals("https://www.wikidata.org/wiki/Q762")); assertTrue(graphBody.getRelationName().equals("isSimilarTo")); assertTrue(graphBody.getResourceUri().equals(ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/2048410/item_I5DUPVW2Q5HT2OQFSVXV7VYODA5P32P6")); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri().equals(ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/2048410/item_I5DUPVW2Q5HT2OQFSVXV7VYODA5P32P6")); } @@ -232,7 +235,7 @@ public void createSemanticTagSpecific() throws IOException, JsonParseException, assertTrue(tagBody.getHttpUri().equals("http://sws.geonames.org/2988506")); assertNotNull(tagBody.getLanguage()); assertTrue(tagBody.getLanguage().equals("en")); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri().equals(ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/09102/_UEDIN_214")); } diff --git a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/EuropeanaLdSearchApiTest.java b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/EuropeanaLdSearchApiTest.java index 12c15cc96..4614be55c 100644 --- a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/EuropeanaLdSearchApiTest.java +++ b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/EuropeanaLdSearchApiTest.java @@ -5,10 +5,12 @@ import java.io.IOException; import java.util.Iterator; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.stanbol.commons.exception.JsonParseException; import org.junit.jupiter.api.Disabled; + import eu.europeana.annotation.client.abstracts.BaseJsonLdApiTest; import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.vocabulary.MotivationTypes; @@ -41,7 +43,7 @@ public void searchAnnotationsWithMultipleTargetsByEachTarget() throws JsonParseE Annotation annotation = europeanaParser.parseAnnotation(null, annotationStr); String resJson = ""; // List idList = new ArrayList(); - Iterator itr = annotation.getTarget().getValues().iterator(); + Iterator itr = annotation.getTarget().get(0).getValues().iterator(); while (itr.hasNext()) { String target = itr.next(); String annotationStrRes = europeanaLdApi.searchLd( @@ -75,7 +77,7 @@ public void searchAnnotationsWithMultipleTargetsByEachResearchId() throws JsonPa , requestBody ); Annotation annotation = europeanaParser.parseAnnotation(null, annotationStr); - Iterator itr = annotation.getTarget().getResourceIds().iterator(); + Iterator itr = annotation.getTarget().get(0).getResourceIds().iterator(); while (itr.hasNext()) { String resourceId = itr.next(); String annotationStrRes = europeanaLdApi.searchLd( diff --git a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchGraphTest.java b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchGraphTest.java index b44aaddb2..16c1c71c2 100644 --- a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchGraphTest.java +++ b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchGraphTest.java @@ -2,10 +2,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; + import java.io.IOException; import java.lang.reflect.InvocationTargetException; + import org.apache.stanbol.commons.exception.JsonParseException; import org.junit.jupiter.api.Test; + import eu.europeana.annotation.client.config.ClientConfiguration; import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.body.GraphBody; @@ -60,7 +63,7 @@ private void validateGraph(Annotation storedAnno) { assertEquals(VALUE_BODY_LINK_RELATION, graphBody.getRelationName()); String VALUE_TARGET_LINK_SEMANTIC_URI = ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/2048410/item_I5DUPVW2Q5HT2OQFSVXV7VYODA5P32P6"; assertEquals(VALUE_TARGET_LINK_SEMANTIC_URI, graphBody.getResourceUri()); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertEquals(VALUE_TARGET_LINK_SEMANTIC_URI, target.getHttpUri()); } diff --git a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchLinksTest.java b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchLinksTest.java index 43994aac5..4a678416d 100644 --- a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchLinksTest.java +++ b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchLinksTest.java @@ -44,7 +44,7 @@ public void searchLink() throws IOException, JsonParseException, IllegalAccessEx */ private void validateLink(Annotation storedAnno) { assertTrue(storedAnno.getMotivation().equals(MotivationTypes.LINKING.name().toLowerCase())); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getValues()); String VALUE_TARGET_LINK_URI = ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/2020601/https___1914_1918_europeana_eu_contributions_19584"; assertTrue(target.getValues().contains(VALUE_TARGET_LINK_URI)); @@ -77,7 +77,7 @@ public void searchSemanticLink() throws IOException, JsonParseException, Illegal */ private void validateSemanticLink(Annotation storedAnno) { assertTrue(storedAnno.getMotivation().equals(MotivationTypes.LINKING.name().toLowerCase())); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); String VALUE_TARGET_LINK_SEMANTIC_URI = ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/2048410/item_I5DUPVW2Q5HT2OQFSVXV7VYODA5P32P6"; assertTrue(target.getHttpUri().equals(VALUE_TARGET_LINK_SEMANTIC_URI)); diff --git a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchSubtitlesTest.java b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchSubtitlesTest.java index 32d816116..34677437a 100644 --- a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchSubtitlesTest.java +++ b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchSubtitlesTest.java @@ -3,10 +3,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.IOException; import java.lang.reflect.InvocationTargetException; + import org.apache.stanbol.commons.exception.JsonParseException; import org.junit.jupiter.api.Test; + import eu.europeana.annotation.client.config.ClientConfiguration; import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.body.impl.FullTextResourceBody; @@ -61,7 +64,7 @@ private void validateSubtitle(Annotation storedAnno) { FullTextResourceBody textBody = ((FullTextResourceBody) storedAnno.getBody()); assertNotNull(textBody.getValue()); assertTrue(textBody.getValue().contains("con il grande finale")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getSource()); assertTrue(target.getSource().equals("http://www.euscreen.eu/item.html?id=EUS_D61E8DF003E30114621A92ABDE846AD7")); assertNotNull(target.getScope()); diff --git a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchTagsTest.java b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchTagsTest.java index f4fc5afd8..336188ccb 100644 --- a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchTagsTest.java +++ b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchTagsTest.java @@ -3,10 +3,13 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.IOException; import java.lang.reflect.InvocationTargetException; + import org.apache.stanbol.commons.exception.JsonParseException; import org.junit.jupiter.api.Test; + import eu.europeana.annotation.client.config.ClientConfiguration; import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.body.TagBody; @@ -64,7 +67,7 @@ private void validateSemanticTag(Annotation storedAnno) { assertTrue(tagBody.getHttpUri().equals("http://www.geonames.org/2988507")); assertNotNull(tagBody.getLanguage()); assertTrue(tagBody.getLanguage().equals("en")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri().equals(ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/09102/_UEDIN_214")); } @@ -106,7 +109,7 @@ private void validateGeoTag(Annotation storedAnno) { assertTrue(placeBody.getLatitude().equals("48.853415")); assertNotNull(placeBody.getLongitude()); assertTrue(placeBody.getLongitude().equals("-102.348800")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri().equals(ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/09102/_UEDIN_214")); } @@ -150,7 +153,7 @@ private void validateTag(Annotation storedAnno) { TagBody tagBody = ((TagBody) storedAnno.getBody()); assertNotNull(tagBody.getValue()); assertTrue(tagBody.getValue().equals("trombone")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri().equals(ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/000002/_UEDIN_214")); } @@ -197,7 +200,7 @@ private void validateSemanticTagSpecific(Annotation storedAnno) { assertTrue(tagBody.getHttpUri().equals("http://sws.geonames.org/2988506")); assertNotNull(tagBody.getLanguage()); assertTrue(tagBody.getLanguage().equals("en")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri().equals(ClientConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/09102/_UEDIN_214")); } diff --git a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchTextualBodyTest.java b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchTextualBodyTest.java index 3392c9417..2d2f6ea0b 100644 --- a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchTextualBodyTest.java +++ b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/search/SearchTextualBodyTest.java @@ -69,7 +69,7 @@ private void validateDescriptionBody(Annotation storedAnno) { TextBody textBody = ((TextBody) storedAnno.getBody()); assertNotNull(textBody.getValue()); assertTrue(textBody.getValue().equals("... this is the textual description of the item ...")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getSource()); assertTrue(target.getSource() .equals("http://www.europeana1914-1918.eu/attachments/2020601/20841.235882.full.jpg")); @@ -123,7 +123,7 @@ private void validateTranscriptionBody(Annotation storedAnno) { FullTextResourceBody textBody = ((FullTextResourceBody) storedAnno.getBody()); assertNotNull(textBody.getValue()); assertTrue(textBody.getValue().equals("... complete transcribed text in HTML ...")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getSource()); assertTrue(target.getSource() .equals("http://www.europeana1914-1918.eu/attachments/2020601/20841.235882.full.jpg")); diff --git a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/tag/SemanticTaggingTest.java b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/tag/SemanticTaggingTest.java index fb7d67ec5..760088df3 100644 --- a/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/tag/SemanticTaggingTest.java +++ b/annotation-client/src/test/java/eu/europeana/annotation/client/integration/webanno/tag/SemanticTaggingTest.java @@ -66,7 +66,7 @@ public void createSemanticTagWebResource() throws IOException, JsonParseExceptio addCreatedAnnotation(storedAnno); log.info(storedAnno.getBody().getInternalType()); assertTrue(storedAnno.getMotivation().equals(MotivationTypes.TAGGING.name().toLowerCase())); - assertTrue(storedAnno.getTarget().getSource() != null); + assertTrue(storedAnno.getTarget().get(0).getSource() != null); assertEquals(storedAnno.getBody().getInternalType(), BodyInternalTypes.SEMANTIC_TAG.name()); } diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/Annotation.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/Annotation.java index 0e1d14216..9f5b67679 100644 --- a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/Annotation.java +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/Annotation.java @@ -1,6 +1,7 @@ package eu.europeana.annotation.definitions.model; import java.util.Date; +import java.util.List; import eu.europeana.annotation.definitions.model.agent.Agent; import eu.europeana.annotation.definitions.model.body.Body; @@ -28,10 +29,10 @@ public interface Annotation { public abstract MotivationTypes getMotivationType(); - public abstract void setTarget(Target target); - - public abstract Target getTarget(); + public abstract void setTarget(List target); + public abstract List getTarget(); + public abstract void setBody(Body body); public abstract Body getBody(); diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/factory/impl/AnnotationObjectFactory.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/factory/impl/AnnotationObjectFactory.java index a5491e5cc..0a43add81 100644 --- a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/factory/impl/AnnotationObjectFactory.java +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/factory/impl/AnnotationObjectFactory.java @@ -4,6 +4,7 @@ import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.factory.AbstractModelObjectFactory; import eu.europeana.annotation.definitions.model.impl.BaseCaptionAnnotation; +import eu.europeana.annotation.definitions.model.impl.BaseHighlightingAnnotation; import eu.europeana.annotation.definitions.model.impl.BaseDescribingAnnotation; import eu.europeana.annotation.definitions.model.impl.BaseImageAnnotation; import eu.europeana.annotation.definitions.model.impl.BaseImageTag; @@ -85,8 +86,11 @@ public Annotation createAnnotationInstance(MotivationTypes motivationType) { annoType = AnnotationTypes.OBJECT_DESCRIBING; break; case LINKFORCONTRIBUTING: - annoType = AnnotationTypes.OBJECT_LINK_FOR_CONTRIBUTING; - break; + annoType = AnnotationTypes.OBJECT_LINK_FOR_CONTRIBUTING; + break; + case HIGHLIGHTING: + annoType = AnnotationTypes.OBJECT_HIGHLIGHTING; + break; default: break; } @@ -141,6 +145,9 @@ public Class getClassForType( case OBJECT_LINK_FOR_CONTRIBUTING: ret = BaseLinkForContributingAnnotation.class; break; + case OBJECT_HIGHLIGHTING: + ret = BaseHighlightingAnnotation.class; + break; default: throw new RuntimeException( "The given type is not supported by the web model"); diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/factory/impl/SelectorObjectFactory.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/factory/impl/SelectorObjectFactory.java index 688c3ba50..c2ecc7f61 100644 --- a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/factory/impl/SelectorObjectFactory.java +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/factory/impl/SelectorObjectFactory.java @@ -3,8 +3,10 @@ import eu.europeana.annotation.definitions.exception.AnnotationAttributeInstantiationException; import eu.europeana.annotation.definitions.model.factory.AbstractModelObjectFactory; import eu.europeana.annotation.definitions.model.resource.selector.Selector; +import eu.europeana.annotation.definitions.model.resource.selector.impl.BaseRDFStatementSelector; import eu.europeana.annotation.definitions.model.resource.selector.impl.BaseSvgSelector; import eu.europeana.annotation.definitions.model.resource.selector.impl.BaseTextPositionSelector; +import eu.europeana.annotation.definitions.model.resource.selector.impl.BaseTextQuoteSelector; import eu.europeana.annotation.definitions.model.resource.selector.impl.SvgRectangleSelector; import eu.europeana.annotation.definitions.model.vocabulary.SelectorTypes; @@ -35,6 +37,12 @@ public Class getClassForType(Enum modelType) case TEXT_POSITION_SELECTOR: returnType = BaseTextPositionSelector.class; break; + case TEXT_QUOTE_SELECTOR: + returnType = BaseTextQuoteSelector.class; + break; + case RDF_STATEMENT_SELECTOR: + returnType = BaseRDFStatementSelector.class; + break; case SVG_RECTANGLE_SELECTOR: returnType = SvgRectangleSelector.class; break; diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/impl/AbstractAnnotation.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/impl/AbstractAnnotation.java index 6370c21d4..b7a7a5907 100644 --- a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/impl/AbstractAnnotation.java +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/impl/AbstractAnnotation.java @@ -1,7 +1,10 @@ package eu.europeana.annotation.definitions.model.impl; import java.util.Date; +import java.util.List; + import org.apache.commons.lang3.StringUtils; + import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.agent.Agent; import eu.europeana.annotation.definitions.model.body.Body; @@ -22,7 +25,7 @@ public abstract class AbstractAnnotation implements Annotation, AnnotationView { private Date created; private Date generated; private Body body; - private Target target; + private List target; protected String motivation; private Style styledBy; protected MotivationTypes motivationType; @@ -80,7 +83,7 @@ public boolean equals(Object other) { && (!this.getTarget().equals(that.getTarget()))) { res = false; } - + if ((this.getMotivation() != null) && (that.getMotivation() != null) && (!this.getMotivation().equals(that.getMotivation()))) { res = false; @@ -121,57 +124,61 @@ public boolean equalsContent(Object other) { Annotation that = (Annotation) other; - boolean res = true; - /** * equality check for all relevant fields. */ if ((this.getType() != null) && (that.getType() != null) && (!this.getType().equals(that.getType()))) { - res = false; + return false; } if ((this.getCreated() != null) && (that.getCreated() != null) && (!this.getCreated().equals(that.getCreated()))) { - res = false; + return false; } if ((this.getCreator() != null) && (that.getCreator() != null) && (!this.getCreator().equalsContent(that.getCreator()))) { - res = false; + return false; } if ((this.getBody() != null) && (that.getBody() != null) && (!this.getBody().equalsContent(that.getBody()))) { - res = false; + return false; } - if ((this.getTarget() != null) && (that.getTarget() != null) - && (!this.getTarget().equalsContent(that.getTarget()))) { - res = false; + if ((this.getTarget() != null) && (that.getTarget() != null)) { + if(this.getTarget().size()!=that.getTarget().size()) { + return false; + } + for(int i=0;i getTarget() { return target; } @Override - public void setTarget(Target target) { + public void setTarget(List target) { this.target = target; } diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/impl/BaseHighlightingAnnotation.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/impl/BaseHighlightingAnnotation.java new file mode 100644 index 000000000..151115fcd --- /dev/null +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/impl/BaseHighlightingAnnotation.java @@ -0,0 +1,13 @@ +package eu.europeana.annotation.definitions.model.impl; + +import eu.europeana.annotation.definitions.model.Annotation; +import eu.europeana.annotation.definitions.model.vocabulary.MotivationTypes; + +public class BaseHighlightingAnnotation extends AbstractAnnotation implements Annotation { + + public BaseHighlightingAnnotation(){ + super(); + motivation = MotivationTypes.HIGHLIGHTING.getOaType(); + } + +} diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/impl/BaseImageAnnotation.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/impl/BaseImageAnnotation.java index e13c9ad28..47342a1d9 100644 --- a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/impl/BaseImageAnnotation.java +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/impl/BaseImageAnnotation.java @@ -13,7 +13,6 @@ public BaseImageAnnotation(){ @Override public String getImageUrl() { - - return getTarget().getHttpUri(); + return getTarget().get(0).getHttpUri(); } } diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/RDFStatementSelector.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/RDFStatementSelector.java new file mode 100644 index 000000000..b0298e10f --- /dev/null +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/RDFStatementSelector.java @@ -0,0 +1,16 @@ +package eu.europeana.annotation.definitions.model.resource.selector; + +public interface RDFStatementSelector extends Selector { + + public abstract String getHasPredicate(); + public abstract void setHasPredicate(String hasPredicate); + + public String getHasSubject(); + public void setHasSubject(String hasSubject); + + public String getHasObject(); + public void setHasObject(String hasObject); + + public abstract TextQuoteSelector getRefinedBy(); + public abstract void setRefinedBy(TextQuoteSelector refinedBy); +} diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/Selector.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/Selector.java index b5bef064a..811f94f8b 100644 --- a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/Selector.java +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/Selector.java @@ -9,7 +9,6 @@ public interface Selector{ public abstract void setDimensionMap(Map dimensionMap); public abstract Map getDimensionMap(); - public abstract void setSelectorTypeEnum(SelectorTypes selectorType); diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/TextQuoteSelector.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/TextQuoteSelector.java new file mode 100644 index 000000000..da5175918 --- /dev/null +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/TextQuoteSelector.java @@ -0,0 +1,15 @@ +package eu.europeana.annotation.definitions.model.resource.selector; + +import java.util.Map; + +public interface TextQuoteSelector extends Selector { + + public abstract String getPrefix(); + public abstract void setPrefix(String prefix); + + public abstract String getSuffix(); + public abstract void setSuffix(String suffix); + + public abstract Map getExact(); + public abstract void setExact(Map exact); +} diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/impl/BaseRDFStatementSelector.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/impl/BaseRDFStatementSelector.java new file mode 100644 index 000000000..7b7ad3611 --- /dev/null +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/impl/BaseRDFStatementSelector.java @@ -0,0 +1,55 @@ +package eu.europeana.annotation.definitions.model.resource.selector.impl; + +import eu.europeana.annotation.definitions.model.resource.selector.RDFStatementSelector; +import eu.europeana.annotation.definitions.model.resource.selector.TextQuoteSelector; +import eu.europeana.annotation.definitions.model.vocabulary.WebAnnotationFields; + +public class BaseRDFStatementSelector extends BaseSelector implements RDFStatementSelector{ + + public BaseRDFStatementSelector() { + super(); + this.setSelectorType(WebAnnotationFields.RDF_STATEMENT_SELECTOR); + } + + private String hasPredicate; + private String hasSubject; + private String hasObject; + private TextQuoteSelector refinedBy; + + @Override + public String getHasPredicate() { + return hasPredicate; + } + @Override + public void setHasPredicate(String hasPredicate) { + this.hasPredicate=hasPredicate; + } + + @Override + public String getHasSubject() { + return hasSubject; + } + @Override + public void setHasSubject(String hasSubject) { + this.hasSubject = hasSubject; + } + + @Override + public String getHasObject() { + return hasObject; + } + @Override + public void setHasObject(String hasObject) { + this.hasObject = hasObject; + } + + @Override + public TextQuoteSelector getRefinedBy() { + return refinedBy; + } + @Override + public void setRefinedBy(TextQuoteSelector refinedBy) { + this.refinedBy=refinedBy; + } + +} diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/impl/BaseTextQuoteSelector.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/impl/BaseTextQuoteSelector.java new file mode 100644 index 000000000..c16587f4f --- /dev/null +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/resource/selector/impl/BaseTextQuoteSelector.java @@ -0,0 +1,49 @@ +package eu.europeana.annotation.definitions.model.resource.selector.impl; + +import java.util.Map; + +import eu.europeana.annotation.definitions.model.resource.selector.TextQuoteSelector; +import eu.europeana.annotation.definitions.model.vocabulary.WebAnnotationFields; + +public class BaseTextQuoteSelector extends BaseSelector implements TextQuoteSelector{ + + public BaseTextQuoteSelector() { + super(); + this.setSelectorType(WebAnnotationFields.TEXT_QUOTE_SELECTOR); + } + + private String prefix; + private String suffix; + private Map exact; + + @Override + public String getPrefix() { + return prefix; + } + + @Override + public void setPrefix(String prefix) { + this.prefix=prefix; + } + + @Override + public String getSuffix() { + return suffix; + } + + @Override + public void setSuffix(String suffix) { + this.suffix=suffix; + } + + @Override + public Map getExact() { + return exact; + } + + @Override + public void setExact(Map exact) { + this.exact=exact; + } + +} diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/utils/AnnotationIdHelper.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/utils/AnnotationIdHelper.java index 56da271b2..2beba39bb 100644 --- a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/utils/AnnotationIdHelper.java +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/utils/AnnotationIdHelper.java @@ -1,8 +1,7 @@ package eu.europeana.annotation.definitions.model.utils; import org.apache.commons.lang3.StringUtils; -import eu.europeana.annotation.definitions.model.Annotation; -import eu.europeana.annotation.definitions.model.target.impl.BaseTarget; + import eu.europeana.annotation.definitions.model.vocabulary.WebAnnotationFields; public class AnnotationIdHelper { @@ -52,24 +51,6 @@ static String[] extractResourceIdPartsFromHttpUri(String httpUri) { return res; } - /** - * Extract resourceId from target.source.httpUri if source exists otherwise from - * target.httpUri. - * - * @param newAnnotation - * @return resourceId string - */ - public static String extractResourceId(Annotation newAnnotation) { - String resourceId = ""; - if (((BaseTarget) newAnnotation.getTarget()).getSourceResource() != null) { - resourceId = extractResourceIdFromHttpUri( - ((BaseTarget) newAnnotation.getTarget()).getSourceResource().getHttpUri()); - } else { - resourceId = extractResourceIdFromHttpUri(newAnnotation.getTarget().getHttpUri()); - } - return resourceId; - } - /** * Extract collection from resourceId. * use {@link #extractResourceIdPartsFromHttpUri(String)} diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/AnnotationScenarioTypes.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/AnnotationScenarioTypes.java index 7a5e42391..3f6e160e4 100644 --- a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/AnnotationScenarioTypes.java +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/AnnotationScenarioTypes.java @@ -10,4 +10,5 @@ public class AnnotationScenarioTypes { public static final String GEO_TAG = "geoTag"; public static final String OBJECT_LINK = "objectLink"; public static final String CONTRIBUTE_LINK = "contributeLink"; + public static final String DEBIAS = "debias"; } diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/AnnotationTypes.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/AnnotationTypes.java index a0543da8c..90761da46 100644 --- a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/AnnotationTypes.java +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/AnnotationTypes.java @@ -8,5 +8,5 @@ @Deprecated public enum AnnotationTypes { - OBJECT_COMMENT, OBJECT_TAG, IMAGE_ANNOTATION, IMAGE_TAG, SEMANTIC_IMAGE_ANNOTATION, OBJECT_LINKING, OBJECT_TRANSCRIPTION, OBJECT_TRANSLATION, OBJECT_SUBTITLLE, OBJECT_CAPTION, OBJECT_DESCRIBING, OBJECT_LINK_FOR_CONTRIBUTING + OBJECT_COMMENT, OBJECT_TAG, IMAGE_ANNOTATION, IMAGE_TAG, SEMANTIC_IMAGE_ANNOTATION, OBJECT_LINKING, OBJECT_TRANSCRIPTION, OBJECT_TRANSLATION, OBJECT_SUBTITLLE, OBJECT_CAPTION, OBJECT_DESCRIBING, OBJECT_LINK_FOR_CONTRIBUTING, OBJECT_HIGHLIGHTING } diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/SelectorTypes.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/SelectorTypes.java index 5b2c05cfe..7e82a14fe 100644 --- a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/SelectorTypes.java +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/SelectorTypes.java @@ -1,5 +1,5 @@ package eu.europeana.annotation.definitions.model.vocabulary; public enum SelectorTypes { - DATA_POSITION_SELECTOR, FRAGMENT_SELECTOR, SVG_SELECTOR, TEXT_POSITION_SELECTOR, TEXT_QUOTE_SELECTOR, SVG_RECTANGLE_SELECTOR + DATA_POSITION_SELECTOR, FRAGMENT_SELECTOR, SVG_SELECTOR, TEXT_POSITION_SELECTOR, TEXT_QUOTE_SELECTOR, RDF_STATEMENT_SELECTOR, SVG_RECTANGLE_SELECTOR } diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/WebAnnotationFields.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/WebAnnotationFields.java index 5610a8dc8..d8af407bb 100644 --- a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/WebAnnotationFields.java +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/WebAnnotationFields.java @@ -148,6 +148,9 @@ public interface WebAnnotationFields extends WebAnnotationModelFields{ public static final String SCOPE = "scope"; public static final String SOURCE = "source"; + public static final String SELECTOR = "selector"; + public static final String RDF_STATEMENT_SELECTOR = "RDFStatementSelector"; + public static final String TEXT_QUOTE_SELECTOR = "TextQuoteSelector"; public static final String RIGHTS = "edmRights"; diff --git a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/fields/WebAnnotationModelFields.java b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/fields/WebAnnotationModelFields.java index 45373f324..f1a23cd0c 100644 --- a/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/fields/WebAnnotationModelFields.java +++ b/annotation-definitions/src/main/java/eu/europeana/annotation/definitions/model/vocabulary/fields/WebAnnotationModelFields.java @@ -94,5 +94,16 @@ public interface WebAnnotationModelFields { public static final String COUNTRY_NAME = "countryName"; public static final String COMMA = ","; + + // selector fields + public static final String HAS_PREDICATE="hasPredicate"; + public static final String HAS_SUBJECT="hasSubject"; + public static final String HAS_OBJECT="hasObject"; + public static final String REFINED_BY="refinedBy"; + public static final String EXACT="exact"; + public static final String EXACT_VALUE="@value"; + public static final String EXACT_LANGUAGE="@language"; + public static final String PREFIX="prefix"; + public static final String SUFFIX="suffix"; } diff --git a/annotation-definitions/src/test/java/eu/europeana/annotation/definitions/model/util/AnnotationTestObjectBuilder.java b/annotation-definitions/src/test/java/eu/europeana/annotation/definitions/model/util/AnnotationTestObjectBuilder.java index 5835e7a7b..1c5cb8636 100644 --- a/annotation-definitions/src/test/java/eu/europeana/annotation/definitions/model/util/AnnotationTestObjectBuilder.java +++ b/annotation-definitions/src/test/java/eu/europeana/annotation/definitions/model/util/AnnotationTestObjectBuilder.java @@ -1,8 +1,11 @@ package eu.europeana.annotation.definitions.model.util; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; + import org.apache.commons.lang3.StringUtils; + import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.agent.Agent; import eu.europeana.annotation.definitions.model.body.Body; @@ -105,7 +108,7 @@ public Annotation createAnnotationJsonInstance() { // set target Target target = buildTarget(); - annotation.setTarget(target); + annotation.setTarget(Arrays.asList(target)); //set Body String comment = "Vlad Tepes"; @@ -160,7 +163,7 @@ public Annotation createBaseObjectTagInstanceWithSameAs(String sameAs, long iden // set target Target target = buildTarget(); - annotation.setTarget(target); + annotation.setTarget(Arrays.asList(target)); //set Body String comment = "Vlad Tepes"; diff --git a/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/factory/PersistentAnnotationFactory.java b/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/factory/PersistentAnnotationFactory.java index 204b2bfaa..611c65c00 100644 --- a/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/factory/PersistentAnnotationFactory.java +++ b/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/factory/PersistentAnnotationFactory.java @@ -8,6 +8,7 @@ import eu.europeana.annotation.mongo.model.PersistentLinkForContributingImpl; import eu.europeana.annotation.mongo.model.PersistentObjectCommentImpl; import eu.europeana.annotation.mongo.model.PersistentObjectDescribingImpl; +import eu.europeana.annotation.mongo.model.PersistentObjectHighlightingImpl; import eu.europeana.annotation.mongo.model.PersistentObjectLinkingImpl; import eu.europeana.annotation.mongo.model.PersistentObjectTagImpl; import eu.europeana.annotation.mongo.model.PersistentObjectTranscriptionImpl; @@ -68,6 +69,9 @@ public Class getAnnotationClass( case OBJECT_LINK_FOR_CONTRIBUTING: ret = PersistentLinkForContributingImpl.class; break; + case OBJECT_HIGHLIGHTING: + ret = PersistentObjectHighlightingImpl.class; + break; default: throw new RuntimeException( "The given type is not supported by the web model"); diff --git a/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/model/PersistentAnnotationImpl.java b/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/model/PersistentAnnotationImpl.java index 8b23d67e4..3b9d6db0c 100644 --- a/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/model/PersistentAnnotationImpl.java +++ b/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/model/PersistentAnnotationImpl.java @@ -1,7 +1,10 @@ package eu.europeana.annotation.mongo.model; import java.util.Date; +import java.util.List; + import org.bson.types.ObjectId; + import dev.morphia.annotations.Embedded; import dev.morphia.annotations.Entity; import dev.morphia.annotations.Field; @@ -41,8 +44,8 @@ public class PersistentAnnotationImpl implements PersistentAnnotation, Persisten @Embedded(PersistentAnnotation.FIELD_BODY) private Body body; @Embedded - private Target target; - + private List target; + @Property(PersistentAnnotation.FIELD_MOTIVATION) private String motivation; private Style styledBy; @@ -93,14 +96,14 @@ public void setBody(Body body) { this.body = body; } - public Target getTarget() { + public List getTarget() { return target; } - public void setTarget(Target target) { + public void setTarget(List target) { this.target = target; } - + public String getMotivation() { return motivation; } diff --git a/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/model/PersistentImageAnnotationImpl.java b/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/model/PersistentImageAnnotationImpl.java index fb24f95de..eaba6be38 100644 --- a/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/model/PersistentImageAnnotationImpl.java +++ b/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/model/PersistentImageAnnotationImpl.java @@ -13,8 +13,7 @@ public PersistentImageAnnotationImpl(){ @Override public String getImageUrl() { - - return getTarget().getHttpUri(); + return getTarget().get(0).getHttpUri(); } } diff --git a/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/model/PersistentObjectHighlightingImpl.java b/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/model/PersistentObjectHighlightingImpl.java new file mode 100644 index 000000000..e52429525 --- /dev/null +++ b/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/model/PersistentObjectHighlightingImpl.java @@ -0,0 +1,16 @@ +package eu.europeana.annotation.mongo.model; + +import eu.europeana.annotation.definitions.model.ObjectTag; +import eu.europeana.annotation.definitions.model.vocabulary.AnnotationTypes; +import eu.europeana.annotation.definitions.model.vocabulary.MotivationTypes; + +public class PersistentObjectHighlightingImpl extends PersistentAnnotationImpl implements ObjectTag{ + + + public PersistentObjectHighlightingImpl(){ + super(); + setInternalType(AnnotationTypes.OBJECT_HIGHLIGHTING.name()); + setMotivation(MotivationTypes.HIGHLIGHTING.getOaType()); + } + +} diff --git a/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/service/PersistentAnnotationServiceImpl.java b/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/service/PersistentAnnotationServiceImpl.java index 449e6c699..97d82915f 100644 --- a/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/service/PersistentAnnotationServiceImpl.java +++ b/annotation-mongo/src/main/java/eu/europeana/annotation/mongo/service/PersistentAnnotationServiceImpl.java @@ -5,10 +5,12 @@ import java.util.Date; import java.util.List; import java.util.stream.Collectors; + import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.bson.types.ObjectId; + import dev.morphia.query.Criteria; import dev.morphia.query.CriteriaContainer; import dev.morphia.query.FindOptions; @@ -97,7 +99,7 @@ private void validatePersistentAnnotation(PersistentAnnotation object, Date now, } protected void validateTarget(PersistentAnnotation object) { - if (object.getTarget() == null) + if (object.getTarget()==null) throw new AnnotationValidationException(AnnotationValidationException.ERROR_NULL_TARGET); } diff --git a/annotation-mongo/src/test/java/eu/europeana/annotation/mongo/service/impl/AnnotationTestDataBuilder.java b/annotation-mongo/src/test/java/eu/europeana/annotation/mongo/service/impl/AnnotationTestDataBuilder.java index 53f15ad09..78b5b52c2 100644 --- a/annotation-mongo/src/test/java/eu/europeana/annotation/mongo/service/impl/AnnotationTestDataBuilder.java +++ b/annotation-mongo/src/test/java/eu/europeana/annotation/mongo/service/impl/AnnotationTestDataBuilder.java @@ -3,7 +3,11 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.util.Arrays; + import javax.annotation.Resource; + import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.ImageAnnotation; import eu.europeana.annotation.definitions.model.ObjectTag; @@ -73,7 +77,7 @@ protected void checkAnnotation(Annotation persistantObject, Annotation storedAnn protected ObjectTag buildObjectTag() { ObjectTag persistentObject = new PersistentObjectTagImpl(); Target target = buildWebpageTarget(); - persistentObject.setTarget(target); + persistentObject.setTarget(Arrays.asList(target)); // set AnnotatedBy Agent creator = new SoftwareAgent(); @@ -119,7 +123,7 @@ protected ImageAnnotation createSimpleAnnotationInstance() { // set target Target target = buildImageTarget(); - persistentObject.setTarget(target); + persistentObject.setTarget(Arrays.asList(target)); //set Body String comment = "Same hair style as in Dracula Untold: https://www.youtube.com/watch?v=_2aWqecTTuE"; diff --git a/annotation-mongo/src/test/java/eu/europeana/annotation/mongo/service/impl/PersistentAnnotationServiceTest.java b/annotation-mongo/src/test/java/eu/europeana/annotation/mongo/service/impl/PersistentAnnotationServiceTest.java index 67799f9ba..d9b179a74 100644 --- a/annotation-mongo/src/test/java/eu/europeana/annotation/mongo/service/impl/PersistentAnnotationServiceTest.java +++ b/annotation-mongo/src/test/java/eu/europeana/annotation/mongo/service/impl/PersistentAnnotationServiceTest.java @@ -5,12 +5,16 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.logging.Logger; import java.util.stream.Collectors; + import javax.annotation.Resource; + import org.bson.types.ObjectId; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Assertions; @@ -20,6 +24,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; + import eu.europeana.annotation.config.AnnotationConfiguration; import eu.europeana.annotation.definitions.exception.AnnotationValidationException; import eu.europeana.annotation.definitions.model.Annotation; @@ -256,8 +261,8 @@ public void testStoreSimpleImageAnnotation() throws AnnotationMongoException { assertNotNull(storedAnnotation.getImageUrl()); assertNotNull(storedAnnotation.getTarget()); - assertNotNull(storedAnnotation.getTarget().getSelector()); - assertNotNull(storedAnnotation.getTarget().getState()); + assertNotNull(storedAnnotation.getTarget().get(0).getSelector()); + assertNotNull(storedAnnotation.getTarget().get(0).getState()); mongoPersistance.remove(storedAnnotation.getIdentifier()); @@ -295,7 +300,7 @@ protected PersistentAnnotation createPersistentAnnotationInstance() { // set target Target target = buildTarget(); - persistentObject.setTarget(target); + persistentObject.setTarget(Arrays.asList(target)); //set Body String comment = "Same hair style as in Dracula Untold: https://www.youtube.com/watch?v=_2aWqecTTuE"; diff --git a/annotation-mongo/src/test/resources/migrations/update_target_to_array.txt b/annotation-mongo/src/test/resources/migrations/update_target_to_array.txt new file mode 100644 index 000000000..10e0cd7b4 --- /dev/null +++ b/annotation-mongo/src/test/resources/migrations/update_target_to_array.txt @@ -0,0 +1,6 @@ +db.getCollection("annotation").find({}).forEach(function(myDocument) { + db.annotation.updateMany( + { _id: myDocument._id }, + { "$set": { "target": [myDocument.target] } } + ); +}) \ No newline at end of file diff --git a/annotation-solr/src/main/java/eu/europeana/annotation/solr/model/internal/SolrAnnotationImpl.java b/annotation-solr/src/main/java/eu/europeana/annotation/solr/model/internal/SolrAnnotationImpl.java index 596079f4e..08164dbb4 100644 --- a/annotation-solr/src/main/java/eu/europeana/annotation/solr/model/internal/SolrAnnotationImpl.java +++ b/annotation-solr/src/main/java/eu/europeana/annotation/solr/model/internal/SolrAnnotationImpl.java @@ -119,6 +119,8 @@ else if(anno.getBody().getInternalType().equalsIgnoreCase(BodyInternalTypes.GEO_ return AnnotationScenarioTypes.OBJECT_LINK; case LINKFORCONTRIBUTING: return AnnotationScenarioTypes.CONTRIBUTE_LINK; + case HIGHLIGHTING: + return AnnotationScenarioTypes.DEBIAS; default: return ""; } diff --git a/annotation-solr/src/main/java/eu/europeana/annotation/solr/service/impl/SolrAnnotationServiceImpl.java b/annotation-solr/src/main/java/eu/europeana/annotation/solr/service/impl/SolrAnnotationServiceImpl.java index 2f646c830..0574bf452 100644 --- a/annotation-solr/src/main/java/eu/europeana/annotation/solr/service/impl/SolrAnnotationServiceImpl.java +++ b/annotation-solr/src/main/java/eu/europeana/annotation/solr/service/impl/SolrAnnotationServiceImpl.java @@ -532,6 +532,9 @@ else if(BodyInternalTypes.isSimpleTagBody(anno.getBody().getInternalType())) { case LINKFORCONTRIBUTING : queries.add(solrUniquenessQueryLinkForContributing(anno, noSelfDupplicate)); break; + case HIGHLIGHTING : + queries.add(solrUniquenessQueryDebias(anno, noSelfDupplicate)); + break; default: break; } @@ -574,7 +577,7 @@ else if(BodyInternalTypes.isSimpleTagBody(anno.getBody().getInternalType())) { private SolrQuery solrUniquenessQueryTranscriptions(Annotation anno, boolean noSelfDupplicate) { SolrQuery query = new SolrQuery(); query.setQuery(WebAnnotationModelFields.MOTIVATION + ":\"" + anno.getMotivationType().getOaType() + "\""); - query.addFilterQuery(SolrAnnotationConstants.TARGET_URI + ":\"" + anno.getTarget().getSource() + "\""); + query.addFilterQuery(SolrAnnotationConstants.TARGET_URI + ":\"" + anno.getTarget().get(0).getSource() + "\""); if(anno.getBody().getLanguage()!=null) { query.addFilterQuery(SolrAnnotationConstants.BODY_VALUE_PREFIX + anno.getBody().getLanguage() + ":*"); } @@ -589,7 +592,7 @@ private SolrQuery solrUniquenessQueryTranscriptions(Annotation anno, boolean noS private SolrQuery solrUniquenessQueryCaptions(Annotation anno, boolean noSelfDupplicate) { SolrQuery query = new SolrQuery(); query.setQuery(WebAnnotationModelFields.MOTIVATION + ":\"" + MotivationTypes.CAPTIONING.getOaType() + "\""); - query.addFilterQuery(SolrAnnotationConstants.TARGET_URI + ":\"" + anno.getTarget().getSource() + "\""); + query.addFilterQuery(SolrAnnotationConstants.TARGET_URI + ":\"" + anno.getTarget().get(0).getSource() + "\""); addNotSelfDupplicateFilter(anno, query, noSelfDupplicate); SolrAnnotationUtils.addQueryFieldFilter(query, SolrAnnotationConstants.ANNO_ID); return query; @@ -599,13 +602,26 @@ private SolrQuery solrUniquenessQueryCaptionsAndSubtitles(Annotation anno, boole SolrQuery query = new SolrQuery(); query.setQuery(WebAnnotationModelFields.MOTIVATION + ":(\"" + MotivationTypes.CAPTIONING.getOaType() + "\"" + " OR " + "\"" + MotivationTypes.SUBTITLING.getOaType() + "\")"); - query.addFilterQuery(SolrAnnotationConstants.TARGET_URI + ":\"" + anno.getTarget().getSource() + "\""); + query.addFilterQuery(SolrAnnotationConstants.TARGET_URI + ":\"" + anno.getTarget().get(0).getSource() + "\""); query.addFilterQuery(SolrAnnotationConstants.BODY_VALUE_PREFIX + anno.getBody().getLanguage() + ":*"); addNotSelfDupplicateFilter(anno, query, noSelfDupplicate); SolrAnnotationUtils.addQueryFieldFilter(query, SolrAnnotationConstants.ANNO_ID); return query; } + private SolrQuery solrUniquenessQueryDebias(Annotation anno, boolean noSelfDupplicate) { + SolrQuery query = new SolrQuery(); + query.setQuery(WebAnnotationModelFields.MOTIVATION + ":\"" + MotivationTypes.HIGHLIGHTING.getOaType() + "\""); + query.addFilterQuery(SolrAnnotationConstants.TARGET_URI + ":\"" + anno.getTarget().get(0).getSource() + "\""); + List bodyUris = extractUriValues(anno.getBody()); + for (int i=0; i 0) { query.addFilterQuery("-" + SolrAnnotationConstants.ANNO_ID + ":" + anno.getIdentifier()); @@ -615,7 +631,7 @@ private void addNotSelfDupplicateFilter(Annotation anno, SolrQuery query, boolea private void addTargetRecordIdFilter(Annotation anno, SolrQuery query) { if(anno.getTarget()!=null) { // extract URIs for target_uri field - List targetUris = extractUriValues(anno.getTarget()); + List targetUris = extractUriValues(anno.getTarget().get(0)); if(targetUris!=null) { // Extract URIs for target_record_id List recordIds = extractRecordIds(targetUris); diff --git a/annotation-solr/src/main/java/eu/europeana/annotation/solr/service/impl/SolrAnnotationUtils.java b/annotation-solr/src/main/java/eu/europeana/annotation/solr/service/impl/SolrAnnotationUtils.java index 39b111288..fc6c7b973 100644 --- a/annotation-solr/src/main/java/eu/europeana/annotation/solr/service/impl/SolrAnnotationUtils.java +++ b/annotation-solr/src/main/java/eu/europeana/annotation/solr/service/impl/SolrAnnotationUtils.java @@ -5,12 +5,14 @@ import java.util.HashMap; import java.util.List; import java.util.Map; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.response.FacetField; import org.apache.solr.client.solrj.response.QueryResponse; import org.apache.solr.common.SolrException; + import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.body.Body; import eu.europeana.annotation.definitions.model.body.GraphBody; @@ -204,17 +206,20 @@ else if (body.getValues() != null) { } protected void processTargetUris(SolrAnnotation solrAnnotation) { - - SpecificResource internetResource = solrAnnotation.getTarget(); - // extract URIs for target_uri field - List targetUris = extractUriValues(internetResource); - solrAnnotation.setTargetUris(targetUris); - - if(targetUris!=null) { - // Extract URIs for target_record_id - List recordIds = extractRecordIds(targetUris); - solrAnnotation.setTargetRecordIds(recordIds); - } + /* + * in case of multiple targets, they all have the same uri, e.g. a source (e.g. in case of the debias targets), + * so we only process the first target + */ + SpecificResource internetResource = solrAnnotation.getTarget().get(0); + + // extract URIs for target_uri field + List targetUris = extractUriValues(internetResource); + if(! targetUris.isEmpty()) { + solrAnnotation.setTargetUris(targetUris); + // Extract URIs for target_record_id + List recordIds = extractRecordIds(targetUris); + solrAnnotation.setTargetRecordIds(recordIds); + } } protected List extractUriValues(SpecificResource specificResource) { diff --git a/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/AnnotationTestsConstants.java b/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/AnnotationTestsConstants.java index f4a441464..9b2608c02 100644 --- a/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/AnnotationTestsConstants.java +++ b/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/AnnotationTestsConstants.java @@ -116,7 +116,9 @@ public String get_TAG_STANDARD_TEST_VALUE_TARGET(String itemDataEndpoint) { public static final String LINK_FOR_CONTRIBUTING_TARGET_SPECIFIC = "/linkforcontributing/link_for_contributing_target_specific.json"; public static final String LINK_FOR_CONTRIBUTING_TARGET_SPECIFIC_ID = "/linkforcontributing/link_for_contributing_target_specific_id.json"; - + public static final String HIGHLIGHTING = "/highlighting/highlighting.json"; + public static final String HIGHLIGHTING_WITHOUT_PREDICATE = "/highlighting/highlighting_without_predicate.json"; + public static final String HIGHLIGHTING_WITHOUT_EXACT = "/highlighting/highlighting_without_exact.json"; public static final String START = "{"; public static final String END = "}"; diff --git a/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationCreateHighlightingIT.java b/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationCreateHighlightingIT.java new file mode 100644 index 000000000..d1a01c0e8 --- /dev/null +++ b/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationCreateHighlightingIT.java @@ -0,0 +1,60 @@ +package eu.europeana.annotation.tests.web; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.apache.stanbol.commons.exception.JsonParseException; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; + +import eu.europeana.annotation.definitions.model.Annotation; +import eu.europeana.annotation.definitions.model.vocabulary.MotivationTypes; +import eu.europeana.annotation.tests.AbstractIntegrationTest; +import eu.europeana.annotation.tests.utils.AnnotationTestUtils; + +@SpringBootTest +@AutoConfigureMockMvc +class AnnotationCreateHighlightingIT extends AbstractIntegrationTest { + + protected Annotation parseHighlighting(String jsonString) throws JsonParseException { + MotivationTypes motivationType = MotivationTypes.HIGHLIGHTING; + return AnnotationTestUtils.parseAnnotation(jsonString, motivationType); + } + + @Test + void createHighlighting() throws Exception { + String requestBody = AnnotationTestUtils.getJsonStringInput(HIGHLIGHTING); + Annotation inputAnno = parseHighlighting(requestBody); + + Annotation storedAnno = createTestAnnotation(HIGHLIGHTING, true); + addToCreatedAnnotations(storedAnno.getIdentifier()); + + // validate the reflection of input in output! + AnnotationTestUtils.validateOutputAgainstInput(storedAnno, inputAnno); + } + + @Test + void createHighlightingWihoutPredicate() throws Exception { + ResponseEntity response = storeTestAnnotation(HIGHLIGHTING_WITHOUT_PREDICATE, true); + assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); + } + + @Test + void createHighlightingWihoutExact() throws Exception { + ResponseEntity response = storeTestAnnotation(HIGHLIGHTING_WITHOUT_EXACT, true); + assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); + } + + @Test + void checkAnnotationDuplicatesCreateHighlighting() throws Exception { + ResponseEntity response = storeTestAnnotation(HIGHLIGHTING, true); + assertEquals(HttpStatus.CREATED, response.getStatusCode()); + Annotation storedAnno = AnnotationTestUtils.parseResponseBody(response); + addToCreatedAnnotations(storedAnno.getIdentifier()); + response = storeTestAnnotation(HIGHLIGHTING, true, null); + assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode()); + } + +} diff --git a/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationCreateIT.java b/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationCreateIT.java index e114293f4..6522d500d 100644 --- a/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationCreateIT.java +++ b/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationCreateIT.java @@ -3,12 +3,15 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.IOException; + import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; + import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.agent.impl.EdmAgent; import eu.europeana.annotation.definitions.model.body.impl.EdmAgentBody; @@ -257,7 +260,7 @@ void createDescribing2() throws Exception { addToCreatedAnnotations(storedAnno.getIdentifier()); assertTrue(storedAnno.getMotivation().equals(MotivationTypes.DESCRIBING.name().toLowerCase())); - assertTrue(storedAnno.getTarget().getSource() != null); + assertTrue(storedAnno.getTarget().get(0).getSource() != null); assertEquals(storedAnno.getBody().getInternalType(), BodyInternalTypes.TEXT.name()); } @@ -328,7 +331,7 @@ void createSemanticTagWebResource() throws Exception { Annotation storedAnno = createTag(SEMANTICTAG_WEB_RESOURCE, false, true); addToCreatedAnnotations(storedAnno.getIdentifier()); assertTrue(storedAnno.getMotivation().equals(MotivationTypes.TAGGING.name().toLowerCase())); - assertTrue(storedAnno.getTarget().getSource() != null); + assertTrue(storedAnno.getTarget().get(0).getSource() != null); assertEquals(storedAnno.getBody().getInternalType(), BodyInternalTypes.SEMANTIC_TAG.name()); } diff --git a/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationSearchIT.java b/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationSearchIT.java index cdb147abc..e6f0171f0 100644 --- a/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationSearchIT.java +++ b/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationSearchIT.java @@ -5,18 +5,21 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; + import java.io.IOException; import java.net.MalformedURLException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.util.Iterator; import java.util.List; + import org.apache.commons.lang3.StringUtils; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpStatus; import org.springframework.test.web.servlet.ResultActions; + import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.body.GraphBody; import eu.europeana.annotation.definitions.model.body.TagBody; @@ -248,7 +251,7 @@ public void searchGeoTag1() throws Exception { assertTrue(placeBody.getLatitude().equals("48.853415")); assertNotNull(placeBody.getLongitude()); assertTrue(placeBody.getLongitude().equals("-102.348800")); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri() .equals(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() @@ -285,7 +288,7 @@ public void searchTag1() throws Exception { TagBody tagBody = ((TagBody) retrievedAnno.getBody()); assertNotNull(tagBody.getValue()); assertTrue(tagBody.getValue().equals("trombone")); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri() .equals(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() @@ -319,7 +322,7 @@ public void searchTagText() throws Exception { TextBody textBody = ((TextBody) retrievedAnno.getBody()); assertNotNull(textBody.getValue()); assertTrue(textBody.getValue().equals("... this is the textual description of the item ...")); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getSource()); assertTrue(target.getSource() .equals("http://www.europeana1914-1918.eu/attachments/2020601/20841.235882.full.jpg")); @@ -348,7 +351,7 @@ public void searchLink1() throws Exception { // validate fields assertTrue(retrievedAnno.getMotivation().equals(MotivationTypes.LINKING.name().toLowerCase())); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getValues()); assertTrue(target.getValues() .contains(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() @@ -374,7 +377,7 @@ public void searchSemanticLink1() throws Exception { // validate fields assertTrue(retrievedAnno.getMotivation().equals(MotivationTypes.LINKING.name().toLowerCase())); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri() .equals(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() @@ -410,7 +413,7 @@ public void searchGraph1() throws Exception { assertTrue(graphBody.getResourceUri() .equals(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/2048410/item_I5DUPVW2Q5HT2OQFSVXV7VYODA5P32P6")); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri() .equals(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() @@ -449,7 +452,7 @@ public void searchSemanticTagSpecific1() throws Exception { assertTrue(tagBody.getHttpUri().equals("http://sws.geonames.org/2988506")); assertNotNull(tagBody.getLanguage()); assertTrue(tagBody.getLanguage().equals("en")); - Target target = retrievedAnno.getTarget(); + Target target = retrievedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri() .equals(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() @@ -495,7 +498,7 @@ public void searchAnnotationsWithMultipleTargetsByEachTarget() throws Exception addToCreatedAnnotations(annotation.getIdentifier()); String resJson = ""; // List idList = new ArrayList(); - Iterator itr = annotation.getTarget().getValues().iterator(); + Iterator itr = annotation.getTarget().get(0).getValues().iterator(); while (itr.hasNext()) { String target = itr.next(); String annotationStrRes = searchAnnotationLd(target, null); @@ -523,7 +526,7 @@ public void searchAnnotationsWithMultipleTargetsByEachResearchId() throws Except Annotation annotation = createAnnotationLd(MotivationTypes.LINKING.name(), annotationNr, requestBody, null); addToCreatedAnnotations(annotation.getIdentifier()); - Iterator itr = annotation.getTarget().getResourceIds().iterator(); + Iterator itr = annotation.getTarget().get(0).getResourceIds().iterator(); while (itr.hasNext()) { String resourceId = itr.next(); String annotationStrRes = searchAnnotationLd(null, resourceId); @@ -576,7 +579,7 @@ private void validateGraph(Annotation storedAnno) throws IOException { AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() + "/2048410/item_I5DUPVW2Q5HT2OQFSVXV7VYODA5P32P6"; assertEquals(VALUE_TARGET_LINK_SEMANTIC_URI, graphBody.getResourceUri()); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertEquals(VALUE_TARGET_LINK_SEMANTIC_URI, target.getHttpUri()); } @@ -610,7 +613,7 @@ public void searchLink2() throws Exception { */ private void validateLink(Annotation storedAnno) throws IOException { assertTrue(storedAnno.getMotivation().equals(MotivationTypes.LINKING.name().toLowerCase())); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getValues()); String VALUE_TARGET_LINK_URI = AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() @@ -648,7 +651,7 @@ public void searchSemanticLink2() throws Exception { */ private void validateSemanticLink(Annotation storedAnno) throws IOException { assertTrue(storedAnno.getMotivation().equals(MotivationTypes.LINKING.name().toLowerCase())); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); String VALUE_TARGET_LINK_SEMANTIC_URI = AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() @@ -693,7 +696,7 @@ private void validateSubtitle(Annotation storedAnno) throws IOException { FullTextResourceBody textBody = ((FullTextResourceBody) storedAnno.getBody()); assertNotNull(textBody.getValue()); assertTrue(textBody.getValue().contains("con il grande finale")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getSource()); assertTrue(target.getSource() .equals("http://www.euscreen.eu/item.html?id=EUS_D61E8DF003E30114621A92ABDE846AD7")); @@ -746,7 +749,7 @@ private void validateSemanticTag(Annotation storedAnno) throws IOException { assertTrue(tagBody.getHttpUri().equals("http://www.geonames.org/2988507")); assertNotNull(tagBody.getLanguage()); assertTrue(tagBody.getLanguage().equals("en")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri() .equals(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() @@ -794,7 +797,7 @@ private void validateGeoTag(Annotation storedAnno) throws IOException { assertTrue(placeBody.getLatitude().equals("48.853415")); assertNotNull(placeBody.getLongitude()); assertTrue(placeBody.getLongitude().equals("-102.348800")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri() .equals(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() @@ -842,7 +845,7 @@ private void validateTag(Annotation storedAnno) throws IOException { TagBody tagBody = ((TagBody) storedAnno.getBody()); assertNotNull(tagBody.getValue()); assertTrue(tagBody.getValue().equals("trombone")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri() .equals(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() @@ -893,7 +896,7 @@ private void validateSemanticTagSpecific(Annotation storedAnno) throws IOExcepti assertTrue(tagBody.getHttpUri().equals("http://sws.geonames.org/2988506")); assertNotNull(tagBody.getLanguage()); assertTrue(tagBody.getLanguage().equals("en")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getHttpUri()); assertTrue(target.getHttpUri() .equals(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint() @@ -945,7 +948,7 @@ private void validateDescriptionBody(Annotation storedAnno) throws IOException { TextBody textBody = ((TextBody) storedAnno.getBody()); assertNotNull(textBody.getValue()); assertTrue(textBody.getValue().equals("... this is the textual description of the item ...")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getSource()); assertTrue(target.getSource() .equals("http://www.europeana1914-1918.eu/attachments/2020601/20841.235882.full.jpg")); @@ -999,7 +1002,7 @@ private void validateTranscriptionBody(Annotation storedAnno) throws IOException FullTextResourceBody textBody = ((FullTextResourceBody) storedAnno.getBody()); assertNotNull(textBody.getValue()); assertTrue(textBody.getValue().equals("... complete transcribed text in HTML ...")); - Target target = storedAnno.getTarget(); + Target target = storedAnno.getTarget().get(0); assertNotNull(target.getSource()); assertTrue(target.getSource() .equals("http://www.europeana1914-1918.eu/attachments/2020601/20841.235882.full.jpg")); diff --git a/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationUpdateIT.java b/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationUpdateIT.java index fb64f8365..60a777719 100644 --- a/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationUpdateIT.java +++ b/annotation-tests/src/integration-test/java/eu/europeana/annotation/tests/web/AnnotationUpdateIT.java @@ -2,12 +2,14 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; + import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; + import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.tests.AbstractIntegrationTest; import eu.europeana.annotation.tests.config.AnnotationTestsConfiguration; @@ -72,7 +74,7 @@ public void updateAnnotation() throws Exception { assertEquals( HttpStatus.OK, response.getStatusCode()); assertNotNull(response.getBody()); assertEquals(TAG_STANDARD_TEST_VALUE_BODY, updatedAnnotation.getBody().getValue()); - assertEquals(get_TAG_STANDARD_TEST_VALUE_TARGET(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint()), updatedAnnotation.getTarget().getHttpUri()); + assertEquals(get_TAG_STANDARD_TEST_VALUE_TARGET(AnnotationTestsConfiguration.getInstance().getPropAnnotationItemDataEndpoint()), updatedAnnotation.getTarget().get(0).getHttpUri()); addToCreatedAnnotations(anno.getIdentifier()); //TODO: search annotation in solr and verify body and target values. diff --git a/annotation-tests/src/integration-test/resources/highlighting/highlighting.json b/annotation-tests/src/integration-test/resources/highlighting/highlighting.json new file mode 100644 index 000000000..874dac2f4 --- /dev/null +++ b/annotation-tests/src/integration-test/resources/highlighting/highlighting.json @@ -0,0 +1,37 @@ +{ + "motivation": "highlighting", + "body": "http://debias.example.org/term/xpto", + "target": [ + { + "source": "http://data.europeana.eu/item/some_cho", + "selector":{ + "type" : "RDFStatementSelector", + "hasPredicate": "dc:title", + "refinedBy" :{ + "type" : "TextQuoteSelector", + "exact": { + "@value": "bias term", + "@language": "en" + }, + "prefix": "same " + } + } + }, + { + "source": "http://data.europeana.eu/item/some_cho", + "selector": { + "type" : "RDFStatementSelector", + "hasPredicate": "dc:description", + "refinedBy" : { + "type" : "TextQuoteSelector", + "exact": { + "@value": "bias term", + "@language": "en" + }, + "prefix": "with a ", + "suffix": ". Also" + } + } + } + ] +} diff --git a/annotation-tests/src/integration-test/resources/highlighting/highlighting_without_exact.json b/annotation-tests/src/integration-test/resources/highlighting/highlighting_without_exact.json new file mode 100644 index 000000000..d447917b7 --- /dev/null +++ b/annotation-tests/src/integration-test/resources/highlighting/highlighting_without_exact.json @@ -0,0 +1,33 @@ +{ + "motivation": "highlighting", + "body": "http://debias.example.org/term/xpto", + "target": [ + { + "source": "http://data.europeana.eu/item/some_cho", + "selector":{ + "type" : "RDFStatementSelector", + "hasPredicate": "dc:title", + "refinedBy" :{ + "type" : "TextQuoteSelector", + "exact": { + "@value": "bias term", + "@language": "en" + }, + "prefix": "same " + } + } + }, + { + "source": "http://data.europeana.eu/item/some_cho", + "selector": { + "type" : "RDFStatementSelector", + "hasPredicate": "dc:description", + "refinedBy" : { + "type" : "TextQuoteSelector", + "prefix": "with a ", + "suffix": ". Also" + } + } + } + ] +} diff --git a/annotation-tests/src/integration-test/resources/highlighting/highlighting_without_predicate.json b/annotation-tests/src/integration-test/resources/highlighting/highlighting_without_predicate.json new file mode 100644 index 000000000..ae0d64d9f --- /dev/null +++ b/annotation-tests/src/integration-test/resources/highlighting/highlighting_without_predicate.json @@ -0,0 +1,36 @@ +{ + "motivation": "highlighting", + "body": "http://debias.example.org/term/xpto", + "target": [ + { + "source": "http://data.europeana.eu/item/some_cho", + "selector":{ + "type" : "RDFStatementSelector", + "refinedBy" :{ + "type" : "TextQuoteSelector", + "exact": { + "@value": "bias term", + "@language": "en" + }, + "prefix": "same " + } + } + }, + { + "source": "http://data.europeana.eu/item/some_cho", + "selector": { + "type" : "RDFStatementSelector", + "hasPredicate": "dc:description", + "refinedBy" : { + "type" : "TextQuoteSelector", + "exact": { + "@value": "bias term", + "@language": "en" + }, + "prefix": "with a ", + "suffix": ". Also" + } + } + } + ] +} diff --git a/annotation-utils/src/main/java/eu/europeana/annotation/utils/JsonUtils.java b/annotation-utils/src/main/java/eu/europeana/annotation/utils/JsonUtils.java index 8f0dea85a..a2aeb222f 100644 --- a/annotation-utils/src/main/java/eu/europeana/annotation/utils/JsonUtils.java +++ b/annotation-utils/src/main/java/eu/europeana/annotation/utils/JsonUtils.java @@ -1,6 +1,5 @@ package eu.europeana.annotation.utils; -import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -10,37 +9,18 @@ import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; -import org.codehaus.jackson.JsonParseException; -import org.codehaus.jackson.JsonParser; -import org.codehaus.jackson.Version; -import org.codehaus.jackson.map.module.SimpleModule; +import org.codehaus.jettison.json.JSONException; +import org.codehaus.jettison.json.JSONObject; import eu.europeana.annotation.definitions.exception.AnnotationInstantiationException; import eu.europeana.annotation.definitions.model.Annotation; -import eu.europeana.annotation.definitions.model.agent.Agent; -import eu.europeana.annotation.definitions.model.body.Body; import eu.europeana.annotation.definitions.model.resource.InternetResource; -import eu.europeana.annotation.definitions.model.resource.selector.Selector; -import eu.europeana.annotation.definitions.model.resource.state.State; -import eu.europeana.annotation.definitions.model.resource.state.impl.BaseState; -import eu.europeana.annotation.definitions.model.resource.style.Style; -import eu.europeana.annotation.definitions.model.resource.style.impl.CssStyle; -import eu.europeana.annotation.definitions.model.selector.shape.Point; -import eu.europeana.annotation.definitions.model.selector.shape.impl.PointImpl; -import eu.europeana.annotation.definitions.model.target.Target; -import eu.europeana.annotation.definitions.model.target.impl.ImageTarget; import eu.europeana.annotation.definitions.model.utils.AnnotationIdHelper; import eu.europeana.annotation.definitions.model.utils.ModelConst; +import eu.europeana.annotation.definitions.model.vocabulary.MotivationTypes; import eu.europeana.annotation.definitions.model.vocabulary.WebAnnotationFields; +import eu.europeana.annotation.utils.parse.AnnotationLdParser; import eu.europeana.annotation.utils.parse.BaseJsonParser; -import eu.europeana.annotation.utils.serialization.AgentDeserializer; -import eu.europeana.annotation.utils.serialization.AnnotationDeserializer; -import eu.europeana.annotation.utils.serialization.BodyDeserializer; -import eu.europeana.annotation.utils.serialization.InternetResourceDeserializer; -import eu.europeana.annotation.utils.serialization.ListDeserializer; -import eu.europeana.annotation.utils.serialization.MapDeserializer; -import eu.europeana.annotation.utils.serialization.SelectorDeserializer; -import eu.europeana.annotation.utils.serialization.TargetDeserializer; /** * @Deprecated the provided methods must be replaced by proper usage of the json to annotation parser @@ -66,50 +46,17 @@ public static AnnotationIdHelper getIdHelper() { * @return */ public static Annotation toAnnotationObject(String json) { - JsonParser parser; - Annotation annotation = null; try { - parser = jsonFactory.createJsonParser(json); - //DeserializationConfig cfg = DeserializerFactory.Config. - SimpleModule module = - new SimpleModule("AnnotationDeserializerModule", - new Version(1, 0, 0, null)); - - module.addDeserializer(Annotation.class, new AnnotationDeserializer()); - module.addDeserializer(Target.class, new TargetDeserializer()); - module.addDeserializer(Body.class, new BodyDeserializer()); -// module.addDeserializer(Concept.class, new ConceptDeserializer()); - module.addDeserializer(Agent.class, new AgentDeserializer()); - module.addDeserializer(Selector.class, new SelectorDeserializer()); - module.addDeserializer(InternetResource.class, new InternetResourceDeserializer()); - //module.addDeserializer(State.class, new StateDeserializer()); - //TODO: needs improvement, otherwise all strings and maps will be converted to String entries - module.addDeserializer(Map.class, new MapDeserializer()); - module.addDeserializer(List.class, new ListDeserializer()); - - //module.addDeserializer(Style.class, new StyleDeserializer()); - module.addAbstractTypeMapping(Point.class, PointImpl.class); - module.addAbstractTypeMapping(Style.class, CssStyle.class); - module.addAbstractTypeMapping(State.class, BaseState.class); -// module.addAbstractTypeMapping(Agent.class, Person.class); - module.addAbstractTypeMapping(Target.class, ImageTarget.class); - - objectMapper.registerModule(module); - - parser.setCodec(objectMapper); - annotation = objectMapper.readValue(parser, Annotation.class); - annotation.setInternalType(annotation.getType()); - if (annotation.getTarget() != null) - setResourceIds(annotation.getTarget()); - if (annotation.getBody() != null) - setResourceIds(annotation.getBody()); - } catch (JsonParseException e) { - throw new AnnotationInstantiationException("Json formating exception!", e); - } catch (IOException e) { - throw new AnnotationInstantiationException("Json reading exception!", e); + AnnotationLdParser annoLdParser = new AnnotationLdParser(); + JSONObject annoJson=new JSONObject(json); + String annoType=annoJson.getString(WebAnnotationFields.TYPE); + return annoLdParser.parseAnnotation(MotivationTypes.getType(annoType), json); } - - return annotation; + catch(JSONException e) { + throw new AnnotationInstantiationException("Json formating exception!", e); + } catch (org.apache.stanbol.commons.exception.JsonParseException e) { + throw new AnnotationInstantiationException("Exception during parsing json into an annotation!", e); + } } /** @@ -152,7 +99,7 @@ public static String mapToStringExt(Map mp) { it.remove(); // avoids a ConcurrentModificationException } if (res.length() > 0) { - res = "[" + res + "]"; + res = "{" + res + "}"; } return res; } diff --git a/annotation-utils/src/main/java/eu/europeana/annotation/utils/parse/AnnotationLdParser.java b/annotation-utils/src/main/java/eu/europeana/annotation/utils/parse/AnnotationLdParser.java index adea58777..99cc27118 100644 --- a/annotation-utils/src/main/java/eu/europeana/annotation/utils/parse/AnnotationLdParser.java +++ b/annotation-utils/src/main/java/eu/europeana/annotation/utils/parse/AnnotationLdParser.java @@ -3,6 +3,7 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; import java.util.List; @@ -33,10 +34,13 @@ import eu.europeana.annotation.definitions.model.factory.impl.AgentObjectFactory; import eu.europeana.annotation.definitions.model.factory.impl.AnnotationObjectFactory; import eu.europeana.annotation.definitions.model.factory.impl.BodyObjectFactory; +import eu.europeana.annotation.definitions.model.factory.impl.SelectorObjectFactory; import eu.europeana.annotation.definitions.model.factory.impl.TargetObjectFactory; import eu.europeana.annotation.definitions.model.resource.InternetResource; import eu.europeana.annotation.definitions.model.resource.SpecificResource; import eu.europeana.annotation.definitions.model.resource.impl.BaseInternetResource; +import eu.europeana.annotation.definitions.model.resource.selector.impl.BaseRDFStatementSelector; +import eu.europeana.annotation.definitions.model.resource.selector.impl.BaseTextQuoteSelector; import eu.europeana.annotation.definitions.model.target.Target; import eu.europeana.annotation.definitions.model.utils.AnnotationIdHelper; import eu.europeana.annotation.definitions.model.utils.TypeUtils; @@ -45,8 +49,10 @@ import eu.europeana.annotation.definitions.model.vocabulary.ContextTypes; import eu.europeana.annotation.definitions.model.vocabulary.MotivationTypes; import eu.europeana.annotation.definitions.model.vocabulary.ResourceTypes; +import eu.europeana.annotation.definitions.model.vocabulary.SelectorTypes; import eu.europeana.annotation.definitions.model.vocabulary.TargetTypes; import eu.europeana.annotation.definitions.model.vocabulary.WebAnnotationFields; +import eu.europeana.annotation.definitions.model.vocabulary.fields.WebAnnotationModelFields; import eu.europeana.annotation.definitions.model.vocabulary.fields.WebAnnotationModelKeywords; /** @@ -279,9 +285,7 @@ private void handleProperty(Annotation anno, JSONObject jo, String property) case WebAnnotationFields.TARGET: // TODO: move the parsing of ID and target in the upper method to // avoid redundant computations - Target target = parseTarget(valueObject); - target.setInputString(valueObject.toString()); - anno.setTarget(target); + parseTarget(anno, valueObject); break; case (WebAnnotationFields.EQUIVALENT_TO): anno.setEquivalentTo((String) valueObject); @@ -342,13 +346,51 @@ private Agent parseCreator(Object valueObject) throws JsonParseException { return parseAgent(AgentTypes.PERSON, valueObject); } - private Target parseTarget(Object valueObject) throws JsonParseException { - if (valueObject instanceof String) - return parseTarget(TargetTypes.WEB_PAGE.name(), (String) valueObject); - else if (valueObject instanceof JSONObject) - return parseTarget((JSONObject) valueObject); - else if (valueObject instanceof JSONArray) - return parseTarget((JSONArray) valueObject); + private List parseTargets(JSONArray valueObject) throws JsonParseException { + List targets=new ArrayList<>(); + try { + for(int i=0;i0) { + if(jsonArray.get(0) instanceof JSONObject) { + //in case we have an array of JSONObject objects, set multiple targets + List targets=parseTargets(jsonArray); + if(! targets.isEmpty()) { + anno.setTarget(targets); + } + } + else { + Target target= parseTarget((JSONArray) valueObject); + target.setInputString(valueObject.toString()); + anno.setTarget(Arrays.asList(target)); + } + } + } else throw new JsonParseException("unsupported target+- deserialization for: " + valueObject); } @@ -663,6 +705,10 @@ private void parseSpecificResourceProperty(SpecificResource specificResource, St parseEuropeanaResourceId(specificResource, value); break; + case WebAnnotationFields.SELECTOR: + parseSelector(specificResource, value); + break; + case WebAnnotationFields.RIGHTS: specificResource.setEdmRights(value.toString()); break; @@ -672,6 +718,83 @@ private void parseSpecificResourceProperty(SpecificResource specificResource, St } } + + protected void parseSelector(SpecificResource specificResource, Object value) throws JsonParseException { + JSONObject json = (JSONObject) value; + try { + String selectorType=json.getString(WebAnnotationModelFields.TYPE); + switch(selectorType) { + case WebAnnotationFields.RDF_STATEMENT_SELECTOR: + parseRdfStatementSelector(specificResource, json); + return; + default: + break; + } + throw new AnnotationAttributeInstantiationException( + "Cannot find appropriate selector type for string: " + selectorType); + } + catch (JSONException e) { + throw new JsonParseException( + "unsupported json deserialization for the selector field with the json: " + json + " " + e.getMessage()); + } + + } + + private void parseRdfStatementSelector(SpecificResource specificResource, JSONObject json) throws JsonParseException { + try { + BaseRDFStatementSelector rdfStatementSelector = (BaseRDFStatementSelector) SelectorObjectFactory.getInstance().createObjectInstance(SelectorTypes.RDF_STATEMENT_SELECTOR); + + String hasPredicate=json.getString(WebAnnotationModelFields.HAS_PREDICATE); + rdfStatementSelector.setHasPredicate(hasPredicate); + + if(json.has(WebAnnotationModelFields.REFINED_BY)) { + JSONObject refinedBy=json.getJSONObject(WebAnnotationModelFields.REFINED_BY); + BaseTextQuoteSelector baseTextQuoteSelector = parseTextQuoteSelector(refinedBy); + rdfStatementSelector.setRefinedBy(baseTextQuoteSelector); + } + + if(json.has(WebAnnotationModelFields.HAS_SUBJECT)) { + rdfStatementSelector.setHasSubject(json.getString(WebAnnotationModelFields.HAS_SUBJECT)); + } + + if(json.has(WebAnnotationModelFields.HAS_OBJECT)) { + rdfStatementSelector.setHasObject(json.getString(WebAnnotationModelFields.HAS_OBJECT)); + } + + specificResource.setSelector(rdfStatementSelector); + } + catch (JSONException e) { + throw new JsonParseException( + "unsupported json deserialization for the RdfStatementSelector json representation: " + json + " " + e.getMessage()); + } + + } + + private BaseTextQuoteSelector parseTextQuoteSelector(JSONObject json) throws JsonParseException { + try { + BaseTextQuoteSelector baseTextQuoteSelector = (BaseTextQuoteSelector) SelectorObjectFactory.getInstance().createObjectInstance(SelectorTypes.TEXT_QUOTE_SELECTOR); + JSONObject exactJson=json.getJSONObject(WebAnnotationModelFields.EXACT); + Map exact=new HashMap<>(); + exact.put(WebAnnotationModelFields.EXACT_VALUE, exactJson.getString(WebAnnotationModelFields.EXACT_VALUE)); + exact.put(WebAnnotationModelFields.EXACT_LANGUAGE, exactJson.getString(WebAnnotationModelFields.EXACT_LANGUAGE)); + baseTextQuoteSelector.setExact(exact); + + if(json.has(WebAnnotationModelFields.PREFIX)) { + baseTextQuoteSelector.setPrefix(json.getString(WebAnnotationModelFields.PREFIX)); + } + + if(json.has(WebAnnotationModelFields.SUFFIX)) { + baseTextQuoteSelector.setSuffix(json.getString(WebAnnotationModelFields.SUFFIX)); + } + + return baseTextQuoteSelector; + } + catch (JSONException e) { + throw new JsonParseException( + "unsupported json deserialization for the TextQuoteSelector json representation: " + json + " " + e.getMessage()); + } + } + protected void parseEuropeanaResourceId(SpecificResource specificResource, Object value) { if(specificResource instanceof Target) { @@ -1002,7 +1125,9 @@ protected BodyInternalTypes guesBodyInternalType(MotivationTypes motivation, Str case TAGGING: return guesBodyTagSubType(value); case LINKFORCONTRIBUTING: - return BodyInternalTypes.SPECIFIC_RESOURCE; + return BodyInternalTypes.SPECIFIC_RESOURCE; + case HIGHLIGHTING: + return BodyInternalTypes.SEMANTIC_TAG; default: break; } @@ -1054,7 +1179,9 @@ else if (valueObject.has(WebAnnotationFields.VALUE)) return BodyInternalTypes.TAG; break; case LINKFORCONTRIBUTING: - return BodyInternalTypes.SPECIFIC_RESOURCE; + return BodyInternalTypes.SPECIFIC_RESOURCE; + case HIGHLIGHTING: + return BodyInternalTypes.SEMANTIC_TAG; default: break; @@ -1063,7 +1190,7 @@ else if (valueObject.has(WebAnnotationFields.VALUE)) throw new AnnotationAttributeInstantiationException( "Cannot find appropriate body type with MotivationType: " + motivation); } - + private BodyInternalTypes guesBodyTagSubType(String value) { // TODO: improve this .. similar check is done in validation.. these two // places should be merged. diff --git a/annotation-utils/src/main/java/eu/europeana/annotation/utils/serialization/TargetDeserializer.java b/annotation-utils/src/main/java/eu/europeana/annotation/utils/serialization/TargetDeserializer.java index 89f057fc5..40e229436 100644 --- a/annotation-utils/src/main/java/eu/europeana/annotation/utils/serialization/TargetDeserializer.java +++ b/annotation-utils/src/main/java/eu/europeana/annotation/utils/serialization/TargetDeserializer.java @@ -31,7 +31,6 @@ public Target deserialize(JsonParser jp, DeserializationContext ctxt) ObjectMapper mapper = (ObjectMapper) jp.getCodec(); ObjectNode root = (ObjectNode) mapper.readTree(jp); Class realClass = null; - Iterator> elementsIterator = root.getFields(); while (elementsIterator.hasNext()) { Entry element = elementsIterator.next(); diff --git a/annotation-utils/src/main/java/eu/europeana/annotation/utils/serialize/AnnotationLdSerializer.java b/annotation-utils/src/main/java/eu/europeana/annotation/utils/serialize/AnnotationLdSerializer.java index 56af605c3..5e51ed36b 100644 --- a/annotation-utils/src/main/java/eu/europeana/annotation/utils/serialize/AnnotationLdSerializer.java +++ b/annotation-utils/src/main/java/eu/europeana/annotation/utils/serialize/AnnotationLdSerializer.java @@ -1,11 +1,13 @@ package eu.europeana.annotation.utils.serialize; import java.util.List; + import org.apache.commons.lang3.StringUtils; import org.apache.stanbol.commons.jsonld.JsonLd; import org.apache.stanbol.commons.jsonld.JsonLdProperty; import org.apache.stanbol.commons.jsonld.JsonLdPropertyValue; import org.apache.stanbol.commons.jsonld.JsonLdResource; + import eu.europeana.annotation.definitions.model.Address; import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.agent.Agent; @@ -18,7 +20,11 @@ import eu.europeana.annotation.definitions.model.graph.Graph; import eu.europeana.annotation.definitions.model.resource.ResourceDescription; import eu.europeana.annotation.definitions.model.resource.SpecificResource; +import eu.europeana.annotation.definitions.model.resource.selector.RDFStatementSelector; +import eu.europeana.annotation.definitions.model.resource.selector.Selector; +import eu.europeana.annotation.definitions.model.resource.selector.TextQuoteSelector; import eu.europeana.annotation.definitions.model.resource.style.Style; +import eu.europeana.annotation.definitions.model.target.Target; import eu.europeana.annotation.definitions.model.utils.AnnotationIdHelper; import eu.europeana.annotation.definitions.model.utils.TypeUtils; import eu.europeana.annotation.definitions.model.vocabulary.AgentTypes; @@ -127,29 +133,38 @@ protected void putExtensions(Annotation annotation, JsonLdResource jsonLdResourc } protected void putTarget(Annotation annotation, JsonLdResource jsonLdResource) { - if (isJsonObjectInput(annotation.getTarget().getInputString())) { - JsonLdProperty targetProperty = addTargetProperty(annotation); - if (targetProperty != null) + if(annotation.getTarget().size()>1) { + JsonLdProperty targetProperty = new JsonLdProperty(WebAnnotationFields.TARGET); + for(Target tar : annotation.getTarget()) { + addTargetPropertyValue(tar, targetProperty); + } + if (targetProperty.getValues()!=null && targetProperty.getValues().size()>0) + jsonLdResource.putProperty(targetProperty); + } + else if (isJsonObjectInput(annotation.getTarget().get(0).getInputString())) { + JsonLdProperty targetProperty = new JsonLdProperty(WebAnnotationFields.TARGET); + addTargetPropertyValue(annotation.getTarget().get(0), targetProperty); + if (targetProperty.getValues()!=null && targetProperty.getValues().size()>0) jsonLdResource.putProperty(targetProperty); } else { if (annotation.getInternalType().equals(AnnotationTypes.OBJECT_LINKING.name())) { - if (annotation.getTarget().getValue() != null){ + if (annotation.getTarget().get(0).getValue() != null){ //1 target - putStringProperty(WebAnnotationFields.TARGET, annotation.getTarget().getValue(), jsonLdResource); + putStringProperty(WebAnnotationFields.TARGET, annotation.getTarget().get(0).getValue(), jsonLdResource); // jsonLdResource.putProperty(WebAnnotationFields.TARGET, annotation.getTarget().getValue()); - }else if (annotation.getTarget().getValues() != null && !annotation.getTarget().getValues().isEmpty()){ + }else if (annotation.getTarget().get(0).getValues() != null && !annotation.getTarget().get(0).getValues().isEmpty()){ //array as target - putListProperty(WebAnnotationFields.TARGET, annotation.getTarget().getValues(), jsonLdResource, true); + putListProperty(WebAnnotationFields.TARGET, annotation.getTarget().get(0).getValues(), jsonLdResource, true); // JsonLdProperty targetProperty = buildListProperty(WebAnnotationFields.TARGET, // annotation.getTarget().getValues(), true); // if (targetProperty != null) // jsonLdResource.putProperty(targetProperty); } } else { - if(annotation.getTarget().getInputString() != null) - jsonLdResource.putProperty(WebAnnotationFields.TARGET, annotation.getTarget().getInputString()); + if(annotation.getTarget().get(0).getInputString() != null) + jsonLdResource.putProperty(WebAnnotationFields.TARGET, annotation.getTarget().get(0).getInputString()); else - jsonLdResource.putProperty(WebAnnotationFields.TARGET, annotation.getTarget().getHttpUri()); + jsonLdResource.putProperty(WebAnnotationFields.TARGET, annotation.getTarget().get(0).getHttpUri()); } } } @@ -169,7 +184,7 @@ protected void putBody(Annotation annotation, JsonLdResource jsonLdResource) { //TODO: check if this is still correct //if no values in the body, //linking have not - if(annotation.getTarget().getInputString() != null) { + if(annotation.getTarget().get(0).getInputString() != null) { putStringProperty(WebAnnotationFields.BODY, annotation.getBody().getInputString(), jsonLdResource); // jsonLdResource.putProperty(WebAnnotationFields.BODY, annotation.getBody().getInputString()); } else { @@ -202,47 +217,50 @@ protected void putGenerator(Annotation annotation, JsonLdResource jsonLdResource } // TODO: review the implementation of this method against last standard specification - private JsonLdProperty addTargetProperty(Annotation annotation) { - JsonLdProperty targetProperty = new JsonLdProperty(WebAnnotationFields.TARGET); + private void addTargetPropertyValue(Target target, JsonLdProperty targetProperty) { JsonLdPropertyValue propertyValue = new JsonLdPropertyValue(); - - if (annotation != null && annotation.getTarget() != null) { + if (target != null) { // if (!StringUtils.isBlank(annotation.getTarget().getInputString())) // propertyValue.getValues().put(WebAnnotationFields.INPUT_STRING, // annotation.getTarget().getInputString()); - List types = annotation.getTarget().getType(); + List types = target.getType(); if (types != null && !types.isEmpty()) putTypeProperty(propertyValue, types); - putSpecificResourceProps(annotation.getTarget(), propertyValue); + putSpecificResourceProps(target, propertyValue); - if (annotation.getTarget().getSelector() != null) { - addSelectorProperty(annotation, propertyValue); + if (target.getSelector() != null) { + addSelectorProperty(target.getSelector(), propertyValue); } - if (propertyValue.getValues().size() == 0) - return null; - targetProperty.addValue(propertyValue); - } else { - return null; + if (propertyValue.getValues().size() != 0) { + targetProperty.addValue(propertyValue); + } } - return targetProperty; } //TODO: review the implementation of this method against latest specifications - protected void addSelectorProperty(Annotation annotation, JsonLdPropertyValue targetPropertyValue) { + protected void addSelectorProperty(Selector selector, JsonLdPropertyValue targetPropertyValue) { + if(selector instanceof RDFStatementSelector) { + addRDFStatementSelectorProperty((RDFStatementSelector) selector, targetPropertyValue); + } + else { + addBaseSelectorProperty(selector, targetPropertyValue); + } + + } + + protected void addBaseSelectorProperty(Selector selector, JsonLdPropertyValue targetPropertyValue) { JsonLdProperty selectorProperty = new JsonLdProperty(WebAnnotationFields.SELECTOR); JsonLdPropertyValue selectorPropertyValue = new JsonLdPropertyValue(); - if (!StringUtils.isBlank(annotation.getTarget().getSelector().getSelectorType())) - selectorPropertyValue.getValues().put(WebAnnotationFields.TYPE, - annotation.getTarget().getSelector().getSelectorType()); + if (!StringUtils.isBlank(selector.getSelectorType())) + selectorPropertyValue.getValues().put(WebAnnotationFields.TYPE, selector.getSelectorType()); - if (annotation.getTarget().getSelector() != null - && !StringUtils.isBlank(annotation.getTarget().getSelector().getDimensionMap().toString())) + if (selector != null && !StringUtils.isBlank(selector.getDimensionMap().toString())) selectorPropertyValue.getValues().put(WebAnnotationFields.DIMENSION_MAP, - JsonUtils.mapToStringExt(annotation.getTarget().getSelector().getDimensionMap())); + JsonUtils.mapToStringExt(selector.getDimensionMap())); if (selectorPropertyValue.getValues().size() != 0) { selectorProperty.addValue(selectorPropertyValue); @@ -250,27 +268,57 @@ protected void addSelectorProperty(Annotation annotation, JsonLdPropertyValue ta } } - //TODO: review the implementation of this method against latest specifications - protected void addSourceProperty(Annotation annotation, JsonLdPropertyValue targetPropertyValue) { - JsonLdProperty sourceProperty = new JsonLdProperty(WebAnnotationFields.SOURCE); - JsonLdPropertyValue sourcePropertyValue = new JsonLdPropertyValue(); + protected void addRDFStatementSelectorProperty(RDFStatementSelector rdfStatementSelector, JsonLdPropertyValue targetPropertyValue) { + JsonLdProperty selectorProperty = new JsonLdProperty(WebAnnotationFields.SELECTOR); + JsonLdPropertyValue selectorPropertyValue = new JsonLdPropertyValue(); + + selectorPropertyValue.putProperty(new JsonLdProperty(WebAnnotationFields.TYPE, rdfStatementSelector.getSelectorType())); + if(rdfStatementSelector.getHasSubject()!=null) { + selectorPropertyValue.putProperty(new JsonLdProperty(WebAnnotationFields.HAS_SUBJECT, rdfStatementSelector.getHasSubject())); + } + + if(rdfStatementSelector.getHasObject()!=null) { + selectorPropertyValue.putProperty(new JsonLdProperty(WebAnnotationFields.HAS_OBJECT, rdfStatementSelector.getHasObject())); + } + + if(rdfStatementSelector.getRefinedBy()!=null) { + addTextQuoteSelectorProperty(rdfStatementSelector.getRefinedBy(), selectorPropertyValue); + } - if (!StringUtils.isBlank(annotation.getTarget().getSourceResource().getContentType())) - sourcePropertyValue.getValues().put(WebAnnotationFields.FORMAT, - annotation.getTarget().getSourceResource().getContentType()); + selectorPropertyValue.putProperty(new JsonLdProperty(WebAnnotationFields.HAS_PREDICATE, rdfStatementSelector.getHasPredicate())); - if (!StringUtils.isBlank(annotation.getTarget().getSourceResource().getHttpUri())) - sourcePropertyValue.getValues().put(WebAnnotationFields.ID, - annotation.getTarget().getSourceResource().getHttpUri()); + selectorProperty.addValue(selectorPropertyValue); - if (sourcePropertyValue.getValues().size() != 0) { - sourceProperty.addValue(sourcePropertyValue); - } + targetPropertyValue.putProperty(selectorProperty); - targetPropertyValue.putProperty(sourceProperty); } + + protected void addTextQuoteSelectorProperty(TextQuoteSelector textQuoteSelector, JsonLdPropertyValue targetPropertyValue) { + JsonLdProperty selectorProperty = new JsonLdProperty(WebAnnotationFields.REFINED_BY); + JsonLdPropertyValue selectorPropertyValue = new JsonLdPropertyValue(); + + selectorPropertyValue.putProperty(new JsonLdProperty(WebAnnotationFields.TYPE, textQuoteSelector.getSelectorType())); + if(textQuoteSelector.getPrefix()!=null) { + selectorPropertyValue.putProperty(new JsonLdProperty(WebAnnotationFields.PREFIX, textQuoteSelector.getPrefix())); + } + + if(textQuoteSelector.getSuffix()!=null) { + selectorPropertyValue.putProperty(new JsonLdProperty(WebAnnotationFields.SUFFIX, textQuoteSelector.getSuffix())); + } + + JsonLdProperty exactProperty = new JsonLdProperty(WebAnnotationFields.EXACT); + JsonLdPropertyValue exactPropertyValue = new JsonLdPropertyValue(); + exactPropertyValue.setValues(textQuoteSelector.getExact()); + exactProperty.addValue(exactPropertyValue); + selectorPropertyValue.putProperty(exactProperty); + + selectorProperty.addValue(selectorPropertyValue); + + targetPropertyValue.putProperty(selectorProperty); + } + // private JsonLdProperty addConceptProperty(Concept concept) { // JsonLdProperty conceptProperty = new JsonLdProperty(WebAnnotationFields.CONCEPT); // JsonLdPropertyValue propertyValue = new JsonLdPropertyValue(); diff --git a/annotation-web/src/main/java/eu/europeana/annotation/web/service/impl/AdminServiceImpl.java b/annotation-web/src/main/java/eu/europeana/annotation/web/service/impl/AdminServiceImpl.java index 10662c880..ed8df8c6e 100644 --- a/annotation-web/src/main/java/eu/europeana/annotation/web/service/impl/AdminServiceImpl.java +++ b/annotation-web/src/main/java/eu/europeana/annotation/web/service/impl/AdminServiceImpl.java @@ -179,53 +179,50 @@ public BatchProcessingStatus updateRecordId(String oldId, String newId) { for (Annotation anno : annotations) { if (!anno.isDisabled()) { - Target annoTarget = anno.getTarget(); - - // update resourceIds - if (annoTarget.getResourceIds() != null) { - List currentResourceIds = annoTarget.getResourceIds(); - List updatedResourceIds = new ArrayList(); - for (String id : currentResourceIds) { - if (id.equals(oldId)) { - String updatedId = newId; - updatedResourceIds.add(updatedId); - } else { - updatedResourceIds.add(id); + for(Target annoTarget : anno.getTarget()) { + // update resourceIds + if (annoTarget.getResourceIds() != null) { + List currentResourceIds = annoTarget.getResourceIds(); + List updatedResourceIds = new ArrayList(); + for (String id : currentResourceIds) { + if (id.equals(oldId)) { + String updatedId = newId; + updatedResourceIds.add(updatedId); + } else { + updatedResourceIds.add(id); + } } + annoTarget.setResourceIds(updatedResourceIds); } - annoTarget.setResourceIds(updatedResourceIds); - } - - // update fields: httpUri, value(s) + inputString - if (annoTarget.getHttpUri() != null) { - String newHttpUri = annoTarget.getHttpUri().replace(oldId, newId); - annoTarget.setHttpUri(newHttpUri); - } - - if (annoTarget.getValue() != null) { - String newValue = annoTarget.getValue().replace(oldId, newId); - annoTarget.setValue(newValue); - // inputString depends on value(s) - annoTarget.setInputString(newValue); - } - - // change "value" and "values" fields, so we only have one of - // them - if (annoTarget.getValues() != null && !annoTarget.getValues().isEmpty()) { - List currentValues = annoTarget.getValues(); - List updatedValues = new ArrayList(); - for (String value : currentValues) { - String updatedValue = value.replace(oldId, newId); - updatedValues.add(updatedValue); + + // update fields: httpUri, value(s) + inputString + if (annoTarget.getHttpUri() != null) { + String newHttpUri = annoTarget.getHttpUri().replace(oldId, newId); + annoTarget.setHttpUri(newHttpUri); + } + + if (annoTarget.getValue() != null) { + String newValue = annoTarget.getValue().replace(oldId, newId); + annoTarget.setValue(newValue); + // inputString depends on value(s) + annoTarget.setInputString(newValue); + } + + // change "value" and "values" fields, so we only have one of + // them + if (annoTarget.getValues() != null && !annoTarget.getValues().isEmpty()) { + List currentValues = annoTarget.getValues(); + List updatedValues = new ArrayList(); + for (String value : currentValues) { + String updatedValue = value.replace(oldId, newId); + updatedValues.add(updatedValue); + } + annoTarget.setValues(updatedValues); + // inputString depends on value(s) + annoTarget.setInputString(updatedValues.toString()); } - annoTarget.setValues(updatedValues); - // inputString depends on value(s) - annoTarget.setInputString(updatedValues.toString()); } - - // replace target - anno.setTarget(annoTarget); - + // update mongo try { PersistentAnnotation storedAnno = (PersistentAnnotation) updateAndReindex( @@ -240,6 +237,7 @@ public BatchProcessingStatus updateRecordId(String oldId, String newId) { status.incrementFailureCount(); throw e; } + } } diff --git a/annotation-web/src/main/java/eu/europeana/annotation/web/validation/BaseAnnotationValidator.java b/annotation-web/src/main/java/eu/europeana/annotation/web/validation/BaseAnnotationValidator.java index d4b716d50..e66bb2344 100644 --- a/annotation-web/src/main/java/eu/europeana/annotation/web/validation/BaseAnnotationValidator.java +++ b/annotation-web/src/main/java/eu/europeana/annotation/web/validation/BaseAnnotationValidator.java @@ -2,13 +2,17 @@ import java.io.IOException; import java.net.URI; +import java.util.List; import java.util.Set; + import javax.annotation.Resource; + import org.apache.commons.lang3.StringUtils; import org.springframework.http.HttpStatus; import org.springframework.lang.NonNull; import org.springframework.security.core.Authentication; import org.xml.sax.SAXParseException; + import eu.europeana.annotation.config.AnnotationConfiguration; import eu.europeana.annotation.definitions.model.Address; import eu.europeana.annotation.definitions.model.Annotation; @@ -19,6 +23,8 @@ import eu.europeana.annotation.definitions.model.body.impl.VcardAddressBody; import eu.europeana.annotation.definitions.model.entity.Place; import eu.europeana.annotation.definitions.model.resource.SpecificResource; +import eu.europeana.annotation.definitions.model.resource.selector.RDFStatementSelector; +import eu.europeana.annotation.definitions.model.resource.selector.Selector; import eu.europeana.annotation.definitions.model.target.Target; import eu.europeana.annotation.definitions.model.vocabulary.BodyInternalTypes; import eu.europeana.annotation.definitions.model.vocabulary.ResourceTypes; @@ -40,9 +46,17 @@ public abstract class BaseAnnotationValidator { - private static final String TRANSCRIPTION_TARGET_SOURCE = "transcription.target.source"; + private static final String TARGET_SOURCE = "target.source"; - private static final String TRANSCRIPTION_TARGET_SCOPE = "transcription.target.scope"; + private static final String TARGET_SCOPE = "target.scope"; + + private static final String TARGET_SELECTOR = "target.selector"; + + private static final String TARGET_SELECTOR_HAS_PREDICATE = "target.selector.hasPredicate"; + + private static final String TARGET_SELECTOR_HAS_SUBJECT = "target.selector.hasSubject"; + + private static final String TARGET_SELECTOR_REFINED_BY_EXACT = "target.selector.refinedBy.exact"; private static final String BODY_EDM_RIGHTS = "body.edmRights"; @@ -460,25 +474,28 @@ public void validateWebAnnotation(Annotation webAnnotation, Authentication authe switch (webAnnotation.getMotivationType()) { case LINKING: - validateLinking(webAnnotation); - break; + validateLinking(webAnnotation); + break; case DESCRIBING: - validateDescribing(webAnnotation); - break; + validateDescribing(webAnnotation); + break; case TAGGING: - validateTag(webAnnotation); - break; + validateTag(webAnnotation); + break; case TRANSCRIBING: case TRANSLATING: - validateTranscriptionOrTranslation(webAnnotation, authentication); - break; + validateTranscriptionOrTranslation(webAnnotation, authentication); + break; case SUBTITLING: case CAPTIONING: - validateSubtitleOrCaption(webAnnotation, authentication); - break; + validateSubtitleOrCaption(webAnnotation, authentication); + break; case LINKFORCONTRIBUTING: - validateLinkForContributing(webAnnotation); - break; + validateLinkForContributing(webAnnotation); + break; + case HIGHLIGHTING: + validateDebias(webAnnotation); + break; default: break; } @@ -592,10 +609,10 @@ protected void validateLinking(Annotation webAnnotation) validateTargetFields(webAnnotation.getTarget()); // validate target URLs against whitelist - if (webAnnotation.getTarget().getValue() != null) { - validateLinkingAgainstWhitelist(webAnnotation.getTarget().getValue()); - } else if (webAnnotation.getTarget().getValues() != null) { - for (String url : webAnnotation.getTarget().getValues()) { + if (webAnnotation.getTarget().get(0).getValue() != null) { + validateLinkingAgainstWhitelist(webAnnotation.getTarget().get(0).getValue()); + } else if (webAnnotation.getTarget().get(0).getValues() != null) { + for (String url : webAnnotation.getTarget().get(0).getValues()) { validateLinkingAgainstWhitelist(url); } } @@ -632,10 +649,16 @@ protected void validateTranscriptionOrTranslation(Annotation webAnnotation, Auth PropertyValidationException { validateBodyExists(webAnnotation.getBody()); validateTranscriptionBodyWithFullTextResource(webAnnotation.getBody(), - webAnnotation.getTarget(), authentication); + webAnnotation.getTarget().get(0), authentication); // validate target validateTargetFields(webAnnotation.getTarget()); } + + protected void validateDebias(Annotation webAnnotation) throws PropertyValidationException { + validateBodyExists(webAnnotation.getBody()); + // validate targets + validateMultipleTargets(webAnnotation.getTarget()); + } /** * Validation of subtitle. @@ -658,7 +681,7 @@ protected void validateSubtitleOrCaption(Annotation webAnnotation, Authenticatio validateTargetFields(webAnnotation.getTarget()); // check mandatory field edmRights - validateEdmRights(body, webAnnotation.getTarget(), authentication); + validateEdmRights(body, webAnnotation.getTarget().get(0), authentication); } protected void validateLinkForContributing(Annotation webAnnotation) @@ -684,8 +707,8 @@ protected void validateLinkForContributing(Annotation webAnnotation) } // specific resources not allowed - String scope = webAnnotation.getTarget().getScope(); - String source = webAnnotation.getTarget().getSource(); + String scope = webAnnotation.getTarget().get(0).getScope(); + String source = webAnnotation.getTarget().get(0).getSource(); if (scope != null || source != null) { throw new RequestBodyValidationException(I18nConstants.INVALID_PARAM_VALUE, I18nConstants.INVALID_PARAM_VALUE, @@ -694,7 +717,7 @@ protected void validateLinkForContributing(Annotation webAnnotation) } // target.id/httpUri is mandatory, however the check for specific resources takes precedence - if (StringUtils.isBlank(webAnnotation.getTarget().getHttpUri())) { + if (StringUtils.isBlank(webAnnotation.getTarget().get(0).getHttpUri())) { throw new PropertyValidationException(I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, new String[] {TARGET}); } @@ -737,41 +760,64 @@ private void validateBodyExists(Body body) throws PropertyValidationException { I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, new String[] {BODY}); } } + + private void validateMultipleTargets(List targets) throws PropertyValidationException { + if(targets==null || targets.isEmpty()) { + throw new PropertyValidationException(I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, + I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, new String[] {TARGET}); + } + /* for now only the specific resource can be in the multiple targets, + * so the same check as in the validateTargetFields method + */ + for(Target target : targets) { + if (target.getSource()!=null || target.getScope()!=null || target.getSelector()!=null) { + validateTargetSpecificResource(target); + } + } + } - private void validateTargetFields(Target target) throws PropertyValidationException { + private void validateTargetFields(List targets) throws PropertyValidationException { // validates that the target value/values/scope (depending on what provided) has a valid base // url // target is mandatory field - if (target == null) { + if (targets == null) { throw new PropertyValidationException(I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, new String[] {TARGET}); } - if (target.getValue() != null) { - // validate simple target - validateTargetSimpleValue(target); - } else if (target.getValues() != null) { - // validate multiple target values - validateTargetMultipleValues(target); - } else if (target.getScope() != null || target.getSource() != null) { - // validate target for specific resource - validateTargetSpecificResource(target); + for(Target target : targets) { + if (target.getValue() != null) { + // validate simple target + validateTargetSimpleValue(target); + } else if (target.getValues() != null) { + // validate multiple target values + validateTargetMultipleValues(target); + } else if (target.getSource()!=null || target.getScope()!=null || target.getSelector()!=null) { + // validate target for specific resource + validateTargetSpecificResource(target); + } } } private void validateTargetSpecificResource(Target target) throws PropertyValidationException { - // scope and source must both be present in the target if one of them is present - if (target.getScope() == null) { - throw new PropertyValidationException(I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, - I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, - new String[] {TRANSCRIPTION_TARGET_SCOPE}); - } + // source must both be present in the target, and beside it (scope or selector) as well if (target.getSource() == null) { throw new PropertyValidationException(I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, - new String[] {TRANSCRIPTION_TARGET_SOURCE}); + new String[] {TARGET_SOURCE}); + } + if (target.getScope()==null && target.getSelector()==null) { + throw new PropertyValidationException(I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, + I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, + new String[] {TARGET_SCOPE + " or " + TARGET_SELECTOR}); + } + + //validate target selectors + if(target.getSelector()!=null) { + validateTargetSelectors(target.getSelector()); } - if (!target.getScope().contains(getConfiguration().getAnnoItemDataEndpoint())) { + + if (target.getScope()!=null && !target.getScope().contains(getConfiguration().getAnnoItemDataEndpoint())) { throw new PropertyValidationException( I18nConstantsAnnotation.ANNOTATION_INVALID_TARGET_BASE_URL, I18nConstantsAnnotation.ANNOTATION_INVALID_TARGET_BASE_URL, @@ -780,10 +826,36 @@ private void validateTargetSpecificResource(Target target) throws PropertyValida // target.source must be a valid url if (!GeneralUtils.isUrl(target.getSource())) { throw new PropertyValidationException( - I18nConstantsAnnotation.ANNOTATION_INVALID_TARGET_SOURCE, - I18nConstantsAnnotation.ANNOTATION_INVALID_TARGET_SOURCE, null); + I18nConstantsAnnotation.ANNOTATION_INVALID_URL, + I18nConstantsAnnotation.ANNOTATION_INVALID_URL, new String[] {TARGET_SOURCE}); } } + + private void validateTargetSelectors(Selector selector) throws PropertyValidationException { + if(WebAnnotationFields.RDF_STATEMENT_SELECTOR.equals(selector.getSelectorType())) { + RDFStatementSelector rdfStatSel=(RDFStatementSelector) selector; + if(StringUtils.isBlank(rdfStatSel.getHasPredicate())) { + throw new PropertyValidationException(I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, + I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, new String[] {TARGET_SELECTOR_HAS_PREDICATE}); + } + + //the exact field in the refinedBy field is mandatory + if(rdfStatSel.getRefinedBy()!=null) { + if(rdfStatSel.getRefinedBy().getExact()==null) { + throw new PropertyValidationException(I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, + I18nConstantsAnnotation.MESSAGE_MISSING_MANDATORY_FIELD, new String[] {TARGET_SELECTOR_REFINED_BY_EXACT}); + } + } + + //if hasSubject exists, it must be a URI + if(! StringUtils.isBlank(rdfStatSel.getHasSubject())) { + if(! GeneralUtils.isUrl(rdfStatSel.getHasSubject())) { + throw new PropertyValidationException(I18nConstantsAnnotation.ANNOTATION_INVALID_URL, + I18nConstantsAnnotation.ANNOTATION_INVALID_URL, new String[] {TARGET_SELECTOR_HAS_SUBJECT}); + } + } + } + } private void validateTargetMultipleValues(Target target) throws PropertyValidationException { for (String targetValue : target.getValues()) { diff --git a/annotation-web/src/main/java/eu/europeana/api/common/config/I18nConstantsAnnotation.java b/annotation-web/src/main/java/eu/europeana/api/common/config/I18nConstantsAnnotation.java index 07e06e413..a25d2f97b 100644 --- a/annotation-web/src/main/java/eu/europeana/api/common/config/I18nConstantsAnnotation.java +++ b/annotation-web/src/main/java/eu/europeana/api/common/config/I18nConstantsAnnotation.java @@ -25,7 +25,7 @@ public interface I18nConstantsAnnotation extends eu.europeana.api.commons.defini String INVALID_HEADER_FORMAT = "error.annotation_invalid_format"; String INVALID_PROPERTY_VALUE = "error.annotation_invalid_property_value"; String ANNOTATION_INVALID_TARGET_BASE_URL = "error.annotation_target_base_url"; - String ANNOTATION_INVALID_TARGET_SOURCE = "error.annotation_target_source"; + String ANNOTATION_INVALID_URL = "error.annotation_invalid_url"; String MESSAGE_IDENTIFIER_NOT_NULL = "error.message_identifier_not_null"; String MESSAGE_IDENTIFIER_NULL = "error.message_identifier_null"; diff --git a/annotation-web/src/main/resources/messages_en.properties b/annotation-web/src/main/resources/messages_en.properties index 30245a011..87ea7d76d 100644 --- a/annotation-web/src/main/resources/messages_en.properties +++ b/annotation-web/src/main/resources/messages_en.properties @@ -43,7 +43,7 @@ error.annotation_media_format_not_supported=Media format not supported for mime error.annotation_transcription_validation=Validation error occurred when validating transcription content: {0}. error.annotation_duplication=Found duplicate annotations with the ids: {0} error.annotation_target_base_url=Invalid annotation target base url, which should contain: {0}. -error.annotation_target_source=Invalid annotation target source (must be a url)! +error.annotation_invalid_url=Invalid url in the field: {0} error.message_identifier_not_null=Identifier must not be set when creating a new Annotation for the given provider! {0} error.message_identifier_null=Identifier must not be null for the given provider! {0} diff --git a/annotation-web/src/main/resources/public/annotation_templates.html b/annotation-web/src/main/resources/public/annotation_templates.html index a2dbb060e..baed077d0 100644 --- a/annotation-web/src/main/resources/public/annotation_templates.html +++ b/annotation-web/src/main/resources/public/annotation_templates.html @@ -40,6 +40,7 @@

Europeana Annotations - Templates (JSON-LD)

  • Create (Object) tag - web resource
  • Create Link For Contributing - Body As Object
  • Create Link For Contributing - Body As String
  • +
  • Create Debias
  • @@ -330,7 +331,55 @@

    Create Link For Contributing - Body As } -
    +
    + +

    Create Debias

    +The json-ld serialization available in the following box is a valid input to be used for the creation of the debias annotations. +    top +
    +(motivation:highlighting) + +
    + diff --git a/annotation-web/src/test/java/eu/europeana/annotation/jsonld/EuropeanaAnnotationLdTest.java b/annotation-web/src/test/java/eu/europeana/annotation/jsonld/EuropeanaAnnotationLdTest.java index 6f820b6a4..8e55b84a9 100644 --- a/annotation-web/src/test/java/eu/europeana/annotation/jsonld/EuropeanaAnnotationLdTest.java +++ b/annotation-web/src/test/java/eu/europeana/annotation/jsonld/EuropeanaAnnotationLdTest.java @@ -3,9 +3,12 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.IOException; import java.net.MalformedURLException; + import javax.annotation.Resource; + import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.stanbol.commons.exception.JsonParseException; @@ -16,7 +19,9 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; + import com.google.gson.Gson; + import eu.europeana.annotation.config.AnnotationConfiguration; import eu.europeana.annotation.definitions.model.Annotation; import eu.europeana.annotation.definitions.model.util.AnnotationTestObjectBuilder; @@ -151,17 +156,17 @@ public void testAnnotationToEuropeanaAnnotationLdWithMissingTargetEntries() { long annoIdentifier = mongoPersistance.generateAnnotationIdentifier(); Annotation baseObjectTag = createBaseObjectTagInstance(annoIdentifier); - baseObjectTag.getTarget().setContentType(null); - baseObjectTag.getTarget().setHttpUri(null); + baseObjectTag.getTarget().get(0).setContentType(null); + baseObjectTag.getTarget().get(0).setHttpUri(null); // baseObjectTag.getTarget().setEuropeanaId(null); - baseObjectTag.getTarget().setLanguage(null); + baseObjectTag.getTarget().get(0).setLanguage(null); // baseObjectTag.getTarget().setMediaType(null); - baseObjectTag.getTarget().setSelector(null); - baseObjectTag.getTarget().setSource(null); - baseObjectTag.getTarget().setState(null); - baseObjectTag.getTarget().setStyleClass(null); - baseObjectTag.getTarget().setType(null); - baseObjectTag.getTarget().setValue(null); + baseObjectTag.getTarget().get(0).setSelector(null); + baseObjectTag.getTarget().get(0).setSource(null); + baseObjectTag.getTarget().get(0).setState(null); + baseObjectTag.getTarget().get(0).setStyleClass(null); + baseObjectTag.getTarget().get(0).setType(null); + baseObjectTag.getTarget().get(0).setValue(null); AnnotationLdSerializer annotation = new AnnotationLdSerializer(baseObjectTag, configuration.getAnnotationBaseUrl()); String actual = annotation.toString(); @@ -437,7 +442,7 @@ public void testAnnotationSelector() throws JsonParseException { /** * add Selector to the Target in Annotation object */ - originalAnnotation.getTarget().setSelector(AnnotationTestObjectBuilder.buildSelector()); + originalAnnotation.getTarget().get(0).setSelector(AnnotationTestObjectBuilder.buildSelector()); /** * convert Annotation object to EuropeanaAnnotationLd object. @@ -458,7 +463,7 @@ public void testAnnotationSelector() throws JsonParseException { // EuropeanaAnnotationLd.toConsole("### convertedAnnotation ###", convertedAnnotationIndent); // log.debug(originalAnnotation.toString()); - assertEquals(originalAnnotation.getTarget().getSelector(), annotationFromEuropeanaAnnotationLd.getTarget().getSelector()); + assertEquals(originalAnnotation.getTarget().get(0).getSelector(), annotationFromEuropeanaAnnotationLd.getTarget().get(0).getSelector()); // Original object does not have EuropeanaUri // originalAnnotation.getTarget().setEuropeanaId(annotationFromEuropeanaAnnotationLd.getTarget().getEuropeanaId()); assertEquals(originalAnnotation, annotationFromEuropeanaAnnotationLd);