From d712790337ecb24819c83d6709decccb55290d16 Mon Sep 17 00:00:00 2001 From: "K. Joeri van der Velde" <82420+joerivandervelde@users.noreply.github.com> Date: Sun, 21 Jan 2024 23:06:20 +0100 Subject: [PATCH 1/2] FDP root now flexible through setting --- .../emx2/fairdatapoint/FAIRDataPoint.java | 86 ++++++++++--------- docs/molgenis/dev_fairdatapoint.md | 9 +- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/backend/molgenis-emx2-fairdatapoint/src/main/java/org/molgenis/emx2/fairdatapoint/FAIRDataPoint.java b/backend/molgenis-emx2-fairdatapoint/src/main/java/org/molgenis/emx2/fairdatapoint/FAIRDataPoint.java index 1ef4760cdf..e4f883a6c1 100644 --- a/backend/molgenis-emx2-fairdatapoint/src/main/java/org/molgenis/emx2/fairdatapoint/FAIRDataPoint.java +++ b/backend/molgenis-emx2-fairdatapoint/src/main/java/org/molgenis/emx2/fairdatapoint/FAIRDataPoint.java @@ -2,7 +2,6 @@ import static org.eclipse.rdf4j.model.util.Values.iri; import static org.eclipse.rdf4j.model.util.Values.literal; -import static org.molgenis.emx2.rdf.RDFService.*; import static org.molgenis.emx2.rdf.RDFUtils.*; import java.io.StringWriter; @@ -12,7 +11,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.eclipse.rdf4j.model.BNode; import org.eclipse.rdf4j.model.IRI; import org.eclipse.rdf4j.model.Model; import org.eclipse.rdf4j.model.ValueFactory; @@ -29,7 +27,7 @@ public class FAIRDataPoint { - // todo: double check cardinality + private static final String FDP_ROOT_METADATA = "FAIR Data Point root metadata"; /** * Constructor @@ -43,7 +41,7 @@ public FAIRDataPoint(Request request, Schema... schemas) { Date currentDateTime = new Date(System.currentTimeMillis()); this.issued = formatter.format(currentDateTime); this.modified = formatter.format(currentDateTime); - this.version = Version.getVersion(); + this.version = "MOLGENIS EMX2 " + Version.getVersion(); this.request = request; this.schemas = schemas; } @@ -125,7 +123,7 @@ public String getResult() throws Exception { String host = extractHost(requestURI); String apiFdp = host + "/api/fdp"; String apiFdpCatalog = apiFdp + "/catalog"; - String apiFdpProfile = apiFdp + "/catalog"; + String apiFdpProfile = apiFdp + "/profile"; String apiFdpIdentifier = apiFdp + "#identifier"; IRI apiFdpEnc = encodedIRI(apiFdp); @@ -137,13 +135,6 @@ public String getResult() throws Exception { Required by FDP specification (https://specs.fairdatapoint.org/) */ builder.add(apiFdpEnc, RDF.TYPE, iri("https://w3id.org/fdp/fdp-o#MetadataService")); - builder.add( - apiFdpEnc, DCTERMS.TITLE, "FAIR Data Point hosted by MOLGENIS-EMX2 at " + apiFdpEnc); - BNode publisher = vf.createBNode(); - builder.add(apiFdpEnc, DCTERMS.PUBLISHER, publisher); - builder.add(publisher, RDF.TYPE, FOAF.AGENT); - builder.add(publisher, FOAF.NAME, "MOLGENIS-EMX2 FAIR Data Point API"); - builder.add(apiFdpEnc, DCTERMS.LICENSE, iri("https://www.gnu.org/licenses/lgpl-3.0.rdf")); builder.add(apiFdpEnc, DCTERMS.CONFORMS_TO, apiFdpProfileEnc); builder.add(apiFdpEnc, DCAT.ENDPOINT_URL, apiFdpEnc); builder.add( @@ -182,37 +173,11 @@ Required by FDP specification (https://specs.fairdatapoint.org/) /* Optional in FDP specification (https://specs.fairdatapoint.org/) */ - builder.add( - apiFdpEnc, - DCTERMS.DESCRIPTION, - "FAIR Data Point hosted by MOLGENIS-EMX2 at " - + apiFdpEnc - + ". This implementation follows the FAIR Data Point Working Draft, 23 August 2021 at https://specs.fairdatapoint.org/."); - builder.add(apiFdpEnc, DCTERMS.LANGUAGE, iri("http://lexvo.org/id/iso639-3/eng")); - BNode rights = vf.createBNode(); - builder.add(apiFdpEnc, DCTERMS.RIGHTS, rights); - builder.add(rights, RDF.TYPE, DCTERMS.RIGHTS_STATEMENT); - builder.add(rights, DCTERMS.DESCRIPTION, "Rights are provided on a per-dataset basis."); - BNode accessRights = vf.createBNode(); - builder.add(apiFdpEnc, DCTERMS.ACCESS_RIGHTS, accessRights); - builder.add(accessRights, RDF.TYPE, DCTERMS.RIGHTS_STATEMENT); - builder.add( - accessRights, DCTERMS.DESCRIPTION, "Access rights are provided on a per-dataset basis."); - BNode vcard = vf.createBNode(); - builder.add(apiFdpEnc, DCAT.CONTACT_POINT, vcard); - builder.add(vcard, RDF.TYPE, VCARD4.KIND); - builder.add(vcard, VCARD4.INDIVIDUAL, "MOLGENIS support desk"); - builder.add(vcard, VCARD4.HAS_EMAIL, "molgenis-support@umcg.nl"); - builder.add(vcard, VCARD4.HAS_URL, "https://molgenis.org/"); builder.add(apiFdpEnc, DCAT.ENDPOINT_DESCRIPTION, encodedIRI(host + "/api/openapi")); builder.add( apiFdpEnc, iri("https://w3id.org/fdp/fdp-o#startDate"), literal(issued, XSD.DATETIME)); builder.add( apiFdpEnc, iri("https://w3id.org/fdp/fdp-o#endDate"), literal(modified, XSD.DATETIME)); - builder.add( - apiFdpEnc, - iri("https://w3id.org/fdp/fdp-o#uiLanguage"), - iri("http://lexvo.org/id/iso639-3/eng")); builder.add(apiFdpEnc, iri("https://w3id.org/fdp/fdp-o#hasSoftwareVersion"), this.version); builder.add( apiFdpEnc, @@ -225,7 +190,6 @@ Not part of FDP specification but good practice (https://specs.fairdatapoint.org builder.add(apiFdpEnc, RDF.TYPE, DCAT.RESOURCE); builder.add(apiFdpEnc, RDF.TYPE, DCAT.DATA_SERVICE); builder.add(apiFdpEnc, RDF.TYPE, iri("https://w3id.org/fdp/fdp-o#FAIRDataPoint")); - builder.add(apiFdpEnc, RDFS.LABEL, "FAIR Data Point hosted by MOLGENIS-EMX2 at " + apiFdpEnc); builder.add(apiFdpEnc, DCTERMS.HAS_VERSION, this.version); builder.add( apiFdpEnc, @@ -240,6 +204,50 @@ Not part of FDP specification but good practice (https://specs.fairdatapoint.org Model model = builder.build(); StringWriter stringWriter = new StringWriter(); Rio.write(model, stringWriter, applicationOntologyFormat, config); + stringWriter.append(getFDPRootMetadata(apiFdpEnc.toString())); return stringWriter.toString(); } + + private String getFDPRootMetadata(String apiFdpEnc) { + for (Schema schema : schemas) { + if (schema.hasSetting(FDP_ROOT_METADATA)) { + return schema.getSettingValue(FDP_ROOT_METADATA); + } + } + Schema schema = addFDPRootMetadataIfMissing(apiFdpEnc); + return schema.getSettingValue(FDP_ROOT_METADATA); + } + + private Schema addFDPRootMetadataIfMissing(String apiFdpEnc) { + schemas[0] + .getMetadata() + .setSetting( + FDP_ROOT_METADATA, + """ + %s + <%s> + dcterms:title "FAIR Data Point hosted by MOLGENIS-EMX2"; + dcterms:publisher [ a foaf:Agent; + foaf:name "MOLGENIS-EMX2 FAIR Data Point API" + ]; + dcterms:license ; + dcterms:description "FAIR Data Point hosted by MOLGENIS-EMX2. This implementation follows the FAIR Data Point Working Draft, 23 August 2021 at https://specs.fairdatapoint.org/."; + dcterms:language lang:eng; + dcterms:rights [ a dcterms:RightsStatement; + dcterms:description "Rights are provided on a per-dataset basis." + ]; + dcterms:accessRights [ a dcterms:RightsStatement; + dcterms:description "Access rights are provided on a per-dataset basis." + ]; + dcat:contactPoint [ a vc:Kind; + vc:Individual "MOLGENIS support desk"; + vc:hasEmail "molgenis-support@umcg.nl"; + vc:hasURL "https://molgenis.org/" + ]; + fdp-o:uiLanguage lang:eng; + rdfs:label "FAIR Data Point hosted by MOLGENIS-EMX2" . + """ + .formatted(System.lineSeparator(), apiFdpEnc)); + return schemas[0]; + } } diff --git a/docs/molgenis/dev_fairdatapoint.md b/docs/molgenis/dev_fairdatapoint.md index 09f6f058f5..9144218b75 100644 --- a/docs/molgenis/dev_fairdatapoint.md +++ b/docs/molgenis/dev_fairdatapoint.md @@ -11,7 +11,14 @@ The easiest way to enable FDP in MOLGENIS EMX2 is by choosing 'FAIR_DATA_HUB' as This will add three tables that will define the content of your FAIR Data Point: [Catalog](https://github.com/molgenis/molgenis-emx2/blob/master/data/fairdatahub/fairdatapoint/demodata/Catalog.csv), [Dataset](https://github.com/molgenis/molgenis-emx2/blob/master/data/fairdatahub/fairdatapoint/demodata/Dataset.csv) and [Distribution](https://github.com/molgenis/molgenis-emx2/blob/master/data/fairdatahub/fairdatapoint/demodata/Distribution.csv). Loading the 'FAIR_DATA_HUB' template including the example data will result in a fully operational FAIR Data Point. -The example data can be used as a reference on how to enter data into the system, but can be safely removed or replaced. +The example data can be used as a reference on how to enter data into the system. +It can be safely removed or replaced. + +Before the FDP can be used, log in as the `admin` user and visit your FDP at `/api/fdp`. +This will add a database setting called _FAIR Data Point root metadata_ to the schema that enables your FDP. +This setting contains a piece of RDF/TTL that is part of your FDP root endpoint which is fully customizable. +Here, you can change the information about your FDP such as title, publisher, contact point and language. +To make changes, go to your FDP-enabling schema, go to Settings, Advanced settings, and click the Edit button for _FAIR Data Point root metadata_. After setting up these tables, this is how its contents are translated to the FDP structure: - Each Dataset contains a reference to one or multiple Catalogs via the `belongsToCatalog` field. From a60106c71996362d0cdd8ba5fd45c06186117c0b Mon Sep 17 00:00:00 2001 From: "K. Joeri van der Velde" <82420+joerivandervelde@users.noreply.github.com> Date: Tue, 23 Jan 2024 10:20:10 +0100 Subject: [PATCH 2/2] Enabled test to meet coverage requirements --- .../org/molgenis/emx2/fairdatapoint/FAIRDataPointTest.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/backend/molgenis-emx2-fairdatapoint/src/test/java/org/molgenis/emx2/fairdatapoint/FAIRDataPointTest.java b/backend/molgenis-emx2-fairdatapoint/src/test/java/org/molgenis/emx2/fairdatapoint/FAIRDataPointTest.java index fcae506055..beec166ad6 100644 --- a/backend/molgenis-emx2-fairdatapoint/src/test/java/org/molgenis/emx2/fairdatapoint/FAIRDataPointTest.java +++ b/backend/molgenis-emx2-fairdatapoint/src/test/java/org/molgenis/emx2/fairdatapoint/FAIRDataPointTest.java @@ -6,7 +6,6 @@ import static org.molgenis.emx2.fairdatapoint.FormatMimeTypes.formatToMediaType; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; import org.molgenis.emx2.Database; @@ -40,7 +39,6 @@ public static void setup() { } @Test - @Disabled public void FDPMetadataSchemaService() throws Exception { Request request = mock(Request.class); when(request.url()).thenReturn("http://localhost:8080/api/fdp"); @@ -50,9 +48,7 @@ public void FDPMetadataSchemaService() throws Exception { assertTrue( result.contains( " a fdp-o:MetadataService, dcat:Resource, dcat:DataService,")); - assertTrue( - result.contains( - "dcterms:title \"FAIR Data Point hosted by MOLGENIS-EMX2 at http://localhost:8080/api/fdp\";")); + assertTrue(result.contains("dcterms:title \"FAIR Data Point hosted by MOLGENIS-EMX2\";")); assertTrue(result.contains("dcterms:publisher [ a foaf:Agent;")); assertTrue(result.contains("foaf:name \"MOLGENIS-EMX2 FAIR Data Point API\"")); assertTrue(