diff --git a/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericController.java b/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericController.java index 87ac3b514..f18e96252 100644 --- a/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericController.java +++ b/src/main/java/nl/dtls/fairdatapoint/api/controller/metadata/GenericController.java @@ -26,6 +26,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import nl.dtls.fairdatapoint.database.rdf.repository.RepositoryMode; +import jakarta.servlet.http.HttpServletResponse; import nl.dtls.fairdatapoint.database.rdf.repository.exception.MetadataRepositoryException; import nl.dtls.fairdatapoint.database.rdf.repository.generic.GenericMetadataRepository; import nl.dtls.fairdatapoint.entity.exception.ForbiddenException; @@ -46,7 +47,9 @@ import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.Value; import org.eclipse.rdf4j.model.impl.LinkedHashModel; +import org.eclipse.rdf4j.model.util.Models; import org.eclipse.rdf4j.model.vocabulary.DCTERMS; +import org.eclipse.rdf4j.model.vocabulary.RDF; import org.eclipse.rdf4j.rio.RDFFormat; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; @@ -149,7 +152,8 @@ public Model getMetaDataExpanded( ) public Model getMetaData( @PathVariable final Optional oUrlPrefix, - @PathVariable final Optional oRecordId + @PathVariable final Optional oRecordId, + HttpServletResponse response ) throws MetadataServiceException { // 1. Init final Model resultRdf = new LinkedHashModel(); @@ -171,7 +175,9 @@ public Model getMetaData( metadataEnhancer.enhanceWithLinks(entityUri, entity, rd, persistentUrl, resultRdf); metadataEnhancer.enhanceWithResourceDefinition(entityUri, rd, resultRdf); - // 5. Create response + enhanceWithSignposting(response, entityUri, resultRdf); + + // 6. Create response return resultRdf; } @@ -416,4 +422,37 @@ private Optional retrieveChildModel(MetadataService childMetadataService, private String createLink(String entityUrl, String childPrefix, int page, int size, String rel) { return format("<%s/page/%s?page=%d&size=%d>; rel=\"%s\"", entityUrl, childPrefix, page, size, rel); } + + private void enhanceWithSignposting(HttpServletResponse response, IRI entityUri, Model resultRdf) { + // author + Models.getProperty(resultRdf, entityUri, DCTERMS.PUBLISHER).ifPresent(pub -> { + addSignpostingHeader(response, pub, "author"); + }); + + // cite-as + addSignpostingHeader(response, entityUri, "cite-as"); + + // describedby + // TODO + + // type + Models.getProperties(resultRdf, entityUri, RDF.TYPE).forEach(type -> { + addSignpostingHeader(response, type, "type"); + }); + + // license + Models.getPropertyIRI(resultRdf, entityUri, DCTERMS.LICENSE).ifPresent(license -> { + addSignpostingHeader(response, license, "license"); + }); + + // item + // TODO + + // collection + // TODO + } + + private void addSignpostingHeader(HttpServletResponse response, Value link, String rel) { + response.addHeader(HttpHeaders.LINK, format("<%s>; rel=\"%s\"", link, rel)); + } } diff --git a/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/SingpostingTest.java b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/SingpostingTest.java new file mode 100644 index 000000000..2e5a72c5c --- /dev/null +++ b/src/test/java/nl/dtls/fairdatapoint/acceptance/metadata/SingpostingTest.java @@ -0,0 +1,60 @@ +/** + * The MIT License + * Copyright © 2017 DTL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +package nl.dtls.fairdatapoint.acceptance.metadata; + +import static java.lang.String.format; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.collection.IsIn.in; +import static org.hamcrest.core.Is.is; +import java.net.URI; +import nl.dtls.fairdatapoint.WebIntegrationTest; +import org.junit.jupiter.api.Test; +import org.springframework.core.ParameterizedTypeReference; +import org.springframework.http.HttpHeaders; +import org.springframework.http.RequestEntity; + +public class SingpostingTest extends WebIntegrationTest { + private URI url(String id) { + return URI.create(format("/catalog/%s", id)); + } + + @Test + public void testCatalogSignpostingHeaders() { + // GIVEN: + var request = RequestEntity + .get(url("catalog-1")) + .header(HttpHeaders.ACCEPT, "text/turtle") + .build(); + var responseType = new ParameterizedTypeReference() {}; + + // WHEN: + var result = client.exchange(request, responseType); + + // THEN: + var linkHeaderMatcher = is(in(result.getHeaders().get(HttpHeaders.LINK))); + assertThat("; rel=\"author\"", linkHeaderMatcher); + assertThat("; rel=\"cite-as\"", linkHeaderMatcher); + assertThat("; rel=\"type\"", linkHeaderMatcher); + assertThat("; rel=\"license\"", linkHeaderMatcher); + } +}