From 036328ed81e013a85b6d14c522aadc4e30499497 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Wed, 4 Sep 2024 12:59:27 +0200 Subject: [PATCH 01/26] fix for #224 --- .../dev/dsf/bpe/v1/service/QuestionnaireResponseHelperImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/v1/service/QuestionnaireResponseHelperImpl.java b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/v1/service/QuestionnaireResponseHelperImpl.java index 0cbdc4090..64773dc77 100644 --- a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/v1/service/QuestionnaireResponseHelperImpl.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/v1/service/QuestionnaireResponseHelperImpl.java @@ -100,6 +100,6 @@ public Type transformQuestionTypeToAnswerType(Questionnaire.QuestionnaireItemCom public String getLocalVersionlessAbsoluteUrl(QuestionnaireResponse questionnaireResponse) { return questionnaireResponse.getIdElement().toVersionless() - .withServerBase(serverBaseUrl, ResourceType.Task.name()).getValue(); + .withServerBase(serverBaseUrl, ResourceType.QuestionnaireResponse.name()).getValue(); } } From 8064f5636955526181c5735b59ac405eeb9071e5 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Wed, 2 Oct 2024 19:27:31 +0200 Subject: [PATCH 02/26] New OrganizationAffiliation role change test case Test case checks whether an entry is deleted from the read_access table for a resource configured for role access by a DIC member (member.com) of the parent organization (parent.com) if the OrganizationAffiliation for that parent/member relationship changes from DIC to HRP. --- .../fhir/dao/AbstractReadAccessDaoTest.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/AbstractReadAccessDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/AbstractReadAccessDaoTest.java index f4b0cb833..565679364 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/AbstractReadAccessDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/AbstractReadAccessDaoTest.java @@ -522,6 +522,49 @@ public void testReadAccessTriggerRoleUpdate() throws Exception assertReadAccessEntryCount(2, 1, v1, READ_ACCESS_TAG_VALUE_ROLE, createdMemberOrg, updatedAff); } + @Test + public void testReadAccessTriggerRoleUpdateRoleChange() throws Exception + { + final OrganizationAffiliationDaoJdbc organizationAffiliationDao = new OrganizationAffiliationDaoJdbc( + defaultDataSource, permanentDeleteDataSource, fhirContext); + + Organization parentOrg = new Organization(); + parentOrg.setActive(true); + parentOrg.addIdentifier().setSystem(ORGANIZATION_IDENTIFIER_SYSTEM).setValue("parent.com"); + + Organization memberOrg = new Organization(); + memberOrg.setActive(true); + memberOrg.addIdentifier().setSystem(ORGANIZATION_IDENTIFIER_SYSTEM).setValue("member.com"); + + OrganizationDao orgDao = new OrganizationDaoJdbc(defaultDataSource, permanentDeleteDataSource, fhirContext); + Organization createdParentOrg = orgDao.create(parentOrg); + Organization createdMemberOrg = orgDao.create(memberOrg); + + OrganizationAffiliation aff = new OrganizationAffiliation(); + aff.setActive(true); + aff.getCodeFirstRep().getCodingFirstRep().setSystem("http://dsf.dev/fhir/CodeSystem/organization-role") + .setCode("DIC"); + aff.getOrganization().setReference("Organization/" + createdParentOrg.getIdElement().getIdPart()); + aff.getParticipatingOrganization().setReference("Organization/" + createdMemberOrg.getIdElement().getIdPart()); + + OrganizationAffiliation createdAff = organizationAffiliationDao.create(aff); + + D d = createResource(); + readAccessHelper.addRole(d, "parent.com", "http://dsf.dev/fhir/CodeSystem/organization-role", "DIC"); + + D v1 = getDao().create(d); + assertEquals(1L, (long) v1.getIdElement().getVersionIdPartAsLong()); + + assertReadAccessEntryCount(2, 1, v1, READ_ACCESS_TAG_VALUE_LOCAL); + assertReadAccessEntryCount(2, 1, v1, READ_ACCESS_TAG_VALUE_ROLE, createdMemberOrg, createdAff); + + createdAff.getCodeFirstRep().getCodingFirstRep().setCode("HRP"); + OrganizationAffiliation updatedAff = organizationAffiliationDao.update(createdAff); + + assertReadAccessEntryCount(1, 1, v1, READ_ACCESS_TAG_VALUE_LOCAL); + assertReadAccessEntryCount(1, 0, v1, READ_ACCESS_TAG_VALUE_ROLE, createdMemberOrg, updatedAff); + } + @Test public void testReadAccessTriggerRoleUpdateMemberOrganizationNonActive() throws Exception { From cc7588a794ae31eada3bea3a42ad2b70dba5c11d Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Wed, 2 Oct 2024 19:32:44 +0200 Subject: [PATCH 03/26] Performance tests for Organization and OrganizationAffiliation updates Added performance test for Organization and OrganizationAffiliation updates with 500.000 rows existing in the tasks table. --- .../dao/OrganizationAffiliationDaoTest.java | 118 ++++++++++++++++++ .../dev/dsf/fhir/dao/OrganizationDaoTest.java | 104 ++++++++++++++- 2 files changed, 219 insertions(+), 3 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java index 42bbb1c95..3c8b2a14f 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java @@ -6,6 +6,8 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.io.IOException; +import java.io.Reader; import java.sql.Connection; import java.sql.SQLException; import java.util.List; @@ -15,6 +17,10 @@ import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.OrganizationAffiliation; import org.junit.Test; +import org.postgresql.copy.CopyManager; +import org.postgresql.core.BaseConnection; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import dev.dsf.fhir.authorization.read.ReadAccessHelper; import dev.dsf.fhir.authorization.read.ReadAccessHelperImpl; @@ -25,6 +31,8 @@ public class OrganizationAffiliationDaoTest extends AbstractReadAccessDaoTest { + private static final Logger logger = LoggerFactory.getLogger(OrganizationAffiliationDaoTest.class); + private static final String identifierSystem = "http://dsf.dev/sid/organization-identifier"; private static final String identifierValue = "identifier.test"; private static final boolean active = true; @@ -315,4 +323,114 @@ public void testExistsNotDeletedByParentOrganizationMemberOrganizationRoleAndNot assertTrue(exists2); } } + + private class TaskAsCsvGeneratorReader extends Reader + { + public static final int LINE_LENGHT = 1615; + + private int currentTask; + private int maxTasks; + + public TaskAsCsvGeneratorReader(int maxTasks) + { + this.maxTasks = maxTasks; + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException + { + if (len != LINE_LENGHT) + throw new IllegalArgumentException("Buffer length " + LINE_LENGHT + " expected, not " + len); + if (off % LINE_LENGHT != 0) + throw new IllegalArgumentException("Buffer offset mod " + LINE_LENGHT + " == 0 expected, not " + + (off & LINE_LENGHT) + " (off = " + off + ")"); + + if (currentTask < maxTasks) + { + String line = generateLine(); + + if (len != LINE_LENGHT) + throw new IllegalArgumentException("Buffer length " + LINE_LENGHT + " expected"); + + System.arraycopy(line.toCharArray(), 0, cbuf, 0, LINE_LENGHT); + currentTask++; + + return LINE_LENGHT; + } + else + return -1; + } + + @Override + public void close() throws IOException + { + } + + private String generateLine() + { + String id = UUID.randomUUID().toString(); + return "${id},3,,\"{\"\"resourceType\"\":\"\"Task\"\",\"\"id\"\":\"\"${id}\"\",\"\"meta\"\":{\"\"versionId\"\":\"\"3\"\",\"\"lastUpdated\"\":\"\"2024-10-01T18:22:06.765+02:00\"\",\"\"profile\"\":[\"\"http://medizininformatik-initiative.de/fhir/StructureDefinition/feasibility-task-execute|1.0\"\"]},\"\"instantiatesCanonical\"\":\"\"http://medizininformatik-initiative.de/bpe/Process/feasibilityExecute|1.0\"\",\"\"status\"\":\"\"completed\"\",\"\"intent\"\":\"\"order\"\",\"\"authoredOn\"\":\"\"2024-10-01T18:22:07+02:00\"\",\"\"requester\"\":{\"\"type\"\":\"\"Organization\"\",\"\"identifier\"\":{\"\"system\"\":\"\"http://dsf.dev/sid/organization-identifier\"\",\"\"value\"\":\"\"organization.com\"\"}},\"\"restriction\"\":{\"\"recipient\"\":[{\"\"type\"\":\"\"Organization\"\",\"\"identifier\"\":{\"\"system\"\":\"\"http://dsf.dev/sid/organization-identifier\"\",\"\"value\"\":\"\"organization.com\"\"}}]},\"\"input\"\":[{\"\"type\"\":{\"\"coding\"\":[{\"\"system\"\":\"\"http://dsf.dev/fhir/CodeSystem/bpmn-message\"\",\"\"code\"\":\"\"message-name\"\"}]},\"\"valueString\"\":\"\"feasibilityExecuteMessage\"\"},{\"\"type\"\":{\"\"coding\"\":[{\"\"system\"\":\"\"http://dsf.dev/fhir/CodeSystem/bpmn-message\"\",\"\"code\"\":\"\"business-key\"\"}]},\"\"valueString\"\":\"\"${business-key}\"\"},{\"\"type\"\":{\"\"coding\"\":[{\"\"system\"\":\"\"http://dsf.dev/fhir/CodeSystem/bpmn-message\"\",\"\"code\"\":\"\"correlation-key\"\"}]},\"\"valueString\"\":\"\"${correlation-key}\"\"},{\"\"type\"\":{\"\"coding\"\":[{\"\"system\"\":\"\"http://medizininformatik-initiative.de/fhir/CodeSystem/feasibility\"\",\"\"code\"\":\"\"measure-reference\"\"}]},\"\"valueReference\"\":{\"\"reference\"\":\"\"https://dsf.fdpg.test.forschen-fuer-gesundheit.de/fhir/Measure/02bb7540-0d99-4c0e-8764-981e545cf646\"\"}}]}\"\n" + .replace("${id}", id).replace("${business-key}", UUID.randomUUID().toString()) + .replace("${correlation-key}", UUID.randomUUID().toString()); + } + } + + @Test + public void testBigUpdate() throws Exception + { + OrganizationDaoJdbc orgDao = new OrganizationDaoJdbc(defaultDataSource, permanentDeleteDataSource, fhirContext); + + Organization memberOrg = new Organization(); + memberOrg.setActive(true); + memberOrg.getIdentifierFirstRep().setSystem(ReadAccessHelper.ORGANIZATION_IDENTIFIER_SYSTEM) + .setValue("organization.com"); + + Organization createdMemberOrg = orgDao.create(memberOrg); + assertNotNull(createdMemberOrg); + + Organization parentOrg = new Organization(); + parentOrg.setActive(true); + parentOrg.getIdentifierFirstRep().setSystem(ReadAccessHelper.ORGANIZATION_IDENTIFIER_SYSTEM) + .setValue("organization.com"); + + Organization createdParentOrg = orgDao.create(parentOrg); + assertNotNull(createdParentOrg); + + OrganizationAffiliation affiliation = new OrganizationAffiliation(); + affiliation.setActive(true); + affiliation.getParticipatingOrganization() + .setReference("Organization/" + createdMemberOrg.getIdElement().getIdPart()); + affiliation.getOrganization().setReference("Organization/" + createdParentOrg.getIdElement().getIdPart()); + affiliation.addCode().getCodingFirstRep().setSystem("role-system").setCode("role-code"); + + OrganizationAffiliation createdAffiliation = dao.create(affiliation); + assertNotNull(createdAffiliation); + + final int taskCount = 500_000; + + logger.info("Inserting {} Task resources ...", taskCount); + try (Connection connection = defaultDataSource.getConnection()) + { + CopyManager copyManager = new CopyManager(connection.unwrap(BaseConnection.class)); + TaskAsCsvGeneratorReader taskGenerator = new TaskAsCsvGeneratorReader(taskCount); + long insertedRows = copyManager.copyIn("COPY tasks FROM STDIN (FORMAT csv)", taskGenerator, + TaskAsCsvGeneratorReader.LINE_LENGHT); + + assertEquals(taskCount, insertedRows); + } + logger.info("Inserting {} Task resources [Done]", taskCount); + + long t0 = System.currentTimeMillis(); + + OrganizationAffiliation updatedAffiliation1 = dao.update(createdAffiliation); + assertNotNull(updatedAffiliation1); + + OrganizationAffiliation updatedAffiliation2 = dao.update(updatedAffiliation1); + assertNotNull(updatedAffiliation2); + + long t1 = System.currentTimeMillis(); + + logger.info("OrganizationAffiliation updates executed in {} ms", t1 - t0); + assertTrue("OrganizationAffiliation updates took longer then 200 ms", t1 - t0 <= 200); + } } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java index 6d89119ac..e2f065921 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java @@ -4,6 +4,8 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.io.IOException; +import java.io.Reader; import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.PreparedStatement; @@ -17,7 +19,11 @@ import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.StringType; import org.junit.Test; +import org.postgresql.copy.CopyManager; +import org.postgresql.core.BaseConnection; import org.postgresql.util.PGobject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import dev.dsf.fhir.authorization.read.ReadAccessHelper; import dev.dsf.fhir.authorization.read.ReadAccessHelperImpl; @@ -27,6 +33,8 @@ public class OrganizationDaoTest extends AbstractReadAccessDaoTest { + private static final Logger logger = LoggerFactory.getLogger(OrganizationDaoTest.class); + private static final String name = "Demo Organization"; private static final boolean active = true; @@ -234,8 +242,8 @@ public void testUpdateWithExistingBinary() throws Exception org.getIdentifierFirstRep().setSystem(ReadAccessHelper.ORGANIZATION_IDENTIFIER_SYSTEM) .setValue("organization.com"); - Organization cretedOrg = dao.create(org); - assertNotNull(cretedOrg); + Organization createdOrg = dao.create(org); + assertNotNull(createdOrg); Binary binary = new Binary(); binary.setContentType("text/plain"); @@ -246,6 +254,96 @@ public void testUpdateWithExistingBinary() throws Exception Binary createdBinary = binaryDao.create(binary); assertNotNull(createdBinary); - dao.update(cretedOrg); + dao.update(createdOrg); + } + + private class TaskAsCsvGeneratorReader extends Reader + { + public static final int LINE_LENGHT = 1615; + + private int currentTask; + private int maxTasks; + + public TaskAsCsvGeneratorReader(int maxTasks) + { + this.maxTasks = maxTasks; + } + + @Override + public int read(char[] cbuf, int off, int len) throws IOException + { + if (len != LINE_LENGHT) + throw new IllegalArgumentException("Buffer length " + LINE_LENGHT + " expected, not " + len); + if (off % LINE_LENGHT != 0) + throw new IllegalArgumentException("Buffer offset mod " + LINE_LENGHT + " == 0 expected, not " + + (off & LINE_LENGHT) + " (off = " + off + ")"); + + if (currentTask < maxTasks) + { + String line = generateLine(); + + if (len != LINE_LENGHT) + throw new IllegalArgumentException("Buffer length " + LINE_LENGHT + " expected"); + + System.arraycopy(line.toCharArray(), 0, cbuf, 0, LINE_LENGHT); + currentTask++; + + return LINE_LENGHT; + } + else + return -1; + } + + @Override + public void close() throws IOException + { + } + + private String generateLine() + { + String id = UUID.randomUUID().toString(); + return "${id},3,,\"{\"\"resourceType\"\":\"\"Task\"\",\"\"id\"\":\"\"${id}\"\",\"\"meta\"\":{\"\"versionId\"\":\"\"3\"\",\"\"lastUpdated\"\":\"\"2024-10-01T18:22:06.765+02:00\"\",\"\"profile\"\":[\"\"http://medizininformatik-initiative.de/fhir/StructureDefinition/feasibility-task-execute|1.0\"\"]},\"\"instantiatesCanonical\"\":\"\"http://medizininformatik-initiative.de/bpe/Process/feasibilityExecute|1.0\"\",\"\"status\"\":\"\"completed\"\",\"\"intent\"\":\"\"order\"\",\"\"authoredOn\"\":\"\"2024-10-01T18:22:07+02:00\"\",\"\"requester\"\":{\"\"type\"\":\"\"Organization\"\",\"\"identifier\"\":{\"\"system\"\":\"\"http://dsf.dev/sid/organization-identifier\"\",\"\"value\"\":\"\"organization.com\"\"}},\"\"restriction\"\":{\"\"recipient\"\":[{\"\"type\"\":\"\"Organization\"\",\"\"identifier\"\":{\"\"system\"\":\"\"http://dsf.dev/sid/organization-identifier\"\",\"\"value\"\":\"\"organization.com\"\"}}]},\"\"input\"\":[{\"\"type\"\":{\"\"coding\"\":[{\"\"system\"\":\"\"http://dsf.dev/fhir/CodeSystem/bpmn-message\"\",\"\"code\"\":\"\"message-name\"\"}]},\"\"valueString\"\":\"\"feasibilityExecuteMessage\"\"},{\"\"type\"\":{\"\"coding\"\":[{\"\"system\"\":\"\"http://dsf.dev/fhir/CodeSystem/bpmn-message\"\",\"\"code\"\":\"\"business-key\"\"}]},\"\"valueString\"\":\"\"${business-key}\"\"},{\"\"type\"\":{\"\"coding\"\":[{\"\"system\"\":\"\"http://dsf.dev/fhir/CodeSystem/bpmn-message\"\",\"\"code\"\":\"\"correlation-key\"\"}]},\"\"valueString\"\":\"\"${correlation-key}\"\"},{\"\"type\"\":{\"\"coding\"\":[{\"\"system\"\":\"\"http://medizininformatik-initiative.de/fhir/CodeSystem/feasibility\"\",\"\"code\"\":\"\"measure-reference\"\"}]},\"\"valueReference\"\":{\"\"reference\"\":\"\"https://dsf.fdpg.test.forschen-fuer-gesundheit.de/fhir/Measure/02bb7540-0d99-4c0e-8764-981e545cf646\"\"}}]}\"\n" + .replace("${id}", id).replace("${business-key}", UUID.randomUUID().toString()) + .replace("${correlation-key}", UUID.randomUUID().toString()); + } + } + + @Test + public void testBigUpdate() throws Exception + { + Organization org = new Organization(); + org.setActive(true); + org.getIdentifierFirstRep().setSystem(ReadAccessHelper.ORGANIZATION_IDENTIFIER_SYSTEM) + .setValue("organization.com"); + + Organization createdOrg = dao.create(org); + assertNotNull(createdOrg); + + final int taskCount = 500_000; + + logger.info("Inserting {} Task resources ...", taskCount); + try (Connection connection = defaultDataSource.getConnection()) + { + CopyManager copyManager = new CopyManager(connection.unwrap(BaseConnection.class)); + TaskAsCsvGeneratorReader taskGenerator = new TaskAsCsvGeneratorReader(taskCount); + long insertedRows = copyManager.copyIn("COPY tasks FROM STDIN (FORMAT csv)", taskGenerator, + TaskAsCsvGeneratorReader.LINE_LENGHT); + + assertEquals(taskCount, insertedRows); + } + logger.info("Inserting {} Task resources [Done]", taskCount); + + long t0 = System.currentTimeMillis(); + + Organization updatedOrg1 = dao.update(createdOrg); + assertNotNull(updatedOrg1); + + Organization updatedOrg2 = dao.update(createdOrg); + assertNotNull(updatedOrg2); + + long t1 = System.currentTimeMillis(); + + logger.info("Organization updates executed in {} ms", t1 - t0); + assertTrue("Organization updates took longer then 200 ms", t1 - t0 <= 200); } } From 5179b8ef904d1df444cadf720a8c7ab2133d3279 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Wed, 2 Oct 2024 19:57:14 +0200 Subject: [PATCH 04/26] code formatting --- .../test/java/dev/dsf/fhir/dao/AbstractReadAccessDaoTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/AbstractReadAccessDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/AbstractReadAccessDaoTest.java index 565679364..134f3ec3a 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/AbstractReadAccessDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/AbstractReadAccessDaoTest.java @@ -560,7 +560,7 @@ public void testReadAccessTriggerRoleUpdateRoleChange() throws Exception createdAff.getCodeFirstRep().getCodingFirstRep().setCode("HRP"); OrganizationAffiliation updatedAff = organizationAffiliationDao.update(createdAff); - + assertReadAccessEntryCount(1, 1, v1, READ_ACCESS_TAG_VALUE_LOCAL); assertReadAccessEntryCount(1, 0, v1, READ_ACCESS_TAG_VALUE_ROLE, createdMemberOrg, updatedAff); } From 2833ce18e692a3bd6599179dccd8ba84030fd34e Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Wed, 2 Oct 2024 19:39:13 +0200 Subject: [PATCH 05/26] version to 1.6.0-SNAPSHOT --- dsf-bpe/dsf-bpe-process-api-v1/pom.xml | 2 +- dsf-bpe/dsf-bpe-server-jetty/pom.xml | 2 +- dsf-bpe/dsf-bpe-server/pom.xml | 2 +- dsf-bpe/pom.xml | 2 +- dsf-common/dsf-common-auth/pom.xml | 2 +- dsf-common/dsf-common-config/pom.xml | 2 +- dsf-common/dsf-common-db/pom.xml | 2 +- dsf-common/dsf-common-documentation/pom.xml | 2 +- dsf-common/dsf-common-jetty/pom.xml | 2 +- dsf-common/dsf-common-status/pom.xml | 2 +- dsf-common/dsf-common-ui/pom.xml | 2 +- dsf-common/pom.xml | 2 +- dsf-fhir/dsf-fhir-auth/pom.xml | 2 +- dsf-fhir/dsf-fhir-rest-adapter/pom.xml | 2 +- dsf-fhir/dsf-fhir-server-jetty/pom.xml | 2 +- dsf-fhir/dsf-fhir-server/pom.xml | 2 +- dsf-fhir/dsf-fhir-validation/pom.xml | 4 ++-- dsf-fhir/dsf-fhir-webservice-client/pom.xml | 2 +- dsf-fhir/dsf-fhir-websocket-client/pom.xml | 2 +- dsf-fhir/pom.xml | 2 +- dsf-tools/dsf-tools-build-info-reader/pom.xml | 2 +- dsf-tools/dsf-tools-bundle-generator/pom.xml | 2 +- dsf-tools/dsf-tools-db-migration/pom.xml | 2 +- dsf-tools/dsf-tools-docker-secrets-reader/pom.xml | 2 +- dsf-tools/dsf-tools-documentation-generator/pom.xml | 2 +- dsf-tools/dsf-tools-proxy-test/pom.xml | 2 +- dsf-tools/dsf-tools-test-data-generator/pom.xml | 2 +- dsf-tools/pom.xml | 2 +- pom.xml | 2 +- 29 files changed, 30 insertions(+), 30 deletions(-) diff --git a/dsf-bpe/dsf-bpe-process-api-v1/pom.xml b/dsf-bpe/dsf-bpe-process-api-v1/pom.xml index 50343d884..590d5aea3 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1/pom.xml +++ b/dsf-bpe/dsf-bpe-process-api-v1/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-bpe-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-bpe/dsf-bpe-server-jetty/pom.xml b/dsf-bpe/dsf-bpe-server-jetty/pom.xml index 8e84e18a6..70ba7f1c9 100755 --- a/dsf-bpe/dsf-bpe-server-jetty/pom.xml +++ b/dsf-bpe/dsf-bpe-server-jetty/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-bpe-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-bpe/dsf-bpe-server/pom.xml b/dsf-bpe/dsf-bpe-server/pom.xml index 76a3ff107..65e045807 100755 --- a/dsf-bpe/dsf-bpe-server/pom.xml +++ b/dsf-bpe/dsf-bpe-server/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-bpe-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-bpe/pom.xml b/dsf-bpe/pom.xml index 7190b7ac2..58ee7676b 100755 --- a/dsf-bpe/pom.xml +++ b/dsf-bpe/pom.xml @@ -7,7 +7,7 @@ dev.dsf dsf-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-common/dsf-common-auth/pom.xml b/dsf-common/dsf-common-auth/pom.xml index fcc61758b..d3e5cdfbb 100644 --- a/dsf-common/dsf-common-auth/pom.xml +++ b/dsf-common/dsf-common-auth/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-common-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-common/dsf-common-config/pom.xml b/dsf-common/dsf-common-config/pom.xml index 195d3c4b4..28dae4c4a 100644 --- a/dsf-common/dsf-common-config/pom.xml +++ b/dsf-common/dsf-common-config/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-common-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-common/dsf-common-db/pom.xml b/dsf-common/dsf-common-db/pom.xml index 87f496fb2..ab0f52280 100644 --- a/dsf-common/dsf-common-db/pom.xml +++ b/dsf-common/dsf-common-db/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-common-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-common/dsf-common-documentation/pom.xml b/dsf-common/dsf-common-documentation/pom.xml index 637a4bc47..c0ee493fd 100644 --- a/dsf-common/dsf-common-documentation/pom.xml +++ b/dsf-common/dsf-common-documentation/pom.xml @@ -6,6 +6,6 @@ dev.dsf dsf-common-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT \ No newline at end of file diff --git a/dsf-common/dsf-common-jetty/pom.xml b/dsf-common/dsf-common-jetty/pom.xml index 975725f9d..121832aa3 100644 --- a/dsf-common/dsf-common-jetty/pom.xml +++ b/dsf-common/dsf-common-jetty/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-common-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-common/dsf-common-status/pom.xml b/dsf-common/dsf-common-status/pom.xml index 0dfca7399..b560bb5f0 100644 --- a/dsf-common/dsf-common-status/pom.xml +++ b/dsf-common/dsf-common-status/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-common-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-common/dsf-common-ui/pom.xml b/dsf-common/dsf-common-ui/pom.xml index 821a7a046..cfd3015e8 100644 --- a/dsf-common/dsf-common-ui/pom.xml +++ b/dsf-common/dsf-common-ui/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-common-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-common/pom.xml b/dsf-common/pom.xml index 4197bced2..b699c5af2 100644 --- a/dsf-common/pom.xml +++ b/dsf-common/pom.xml @@ -7,7 +7,7 @@ dev.dsf dsf-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-fhir/dsf-fhir-auth/pom.xml b/dsf-fhir/dsf-fhir-auth/pom.xml index f3388a0c0..159d12a0b 100644 --- a/dsf-fhir/dsf-fhir-auth/pom.xml +++ b/dsf-fhir/dsf-fhir-auth/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-fhir/dsf-fhir-rest-adapter/pom.xml b/dsf-fhir/dsf-fhir-rest-adapter/pom.xml index 3b732a35a..9843f2377 100755 --- a/dsf-fhir/dsf-fhir-rest-adapter/pom.xml +++ b/dsf-fhir/dsf-fhir-rest-adapter/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-fhir/dsf-fhir-server-jetty/pom.xml b/dsf-fhir/dsf-fhir-server-jetty/pom.xml index 5340dd4f7..2f4aa481c 100755 --- a/dsf-fhir/dsf-fhir-server-jetty/pom.xml +++ b/dsf-fhir/dsf-fhir-server-jetty/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-fhir/dsf-fhir-server/pom.xml b/dsf-fhir/dsf-fhir-server/pom.xml index c2ab309ba..3a3a95258 100755 --- a/dsf-fhir/dsf-fhir-server/pom.xml +++ b/dsf-fhir/dsf-fhir-server/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-fhir/dsf-fhir-validation/pom.xml b/dsf-fhir/dsf-fhir-validation/pom.xml index d31de29c6..74c96a2bb 100644 --- a/dsf-fhir/dsf-fhir-validation/pom.xml +++ b/dsf-fhir/dsf-fhir-validation/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT @@ -104,7 +104,7 @@ - diff --git a/dsf-fhir/dsf-fhir-webservice-client/pom.xml b/dsf-fhir/dsf-fhir-webservice-client/pom.xml index bf75b2ee5..50ccd3e90 100755 --- a/dsf-fhir/dsf-fhir-webservice-client/pom.xml +++ b/dsf-fhir/dsf-fhir-webservice-client/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-fhir/dsf-fhir-websocket-client/pom.xml b/dsf-fhir/dsf-fhir-websocket-client/pom.xml index be59b1edf..f433481d5 100755 --- a/dsf-fhir/dsf-fhir-websocket-client/pom.xml +++ b/dsf-fhir/dsf-fhir-websocket-client/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-fhir/pom.xml b/dsf-fhir/pom.xml index 5f1f43b29..b367ebbaa 100755 --- a/dsf-fhir/pom.xml +++ b/dsf-fhir/pom.xml @@ -7,7 +7,7 @@ dev.dsf dsf-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-tools/dsf-tools-build-info-reader/pom.xml b/dsf-tools/dsf-tools-build-info-reader/pom.xml index 2e0984977..2143e2a03 100644 --- a/dsf-tools/dsf-tools-build-info-reader/pom.xml +++ b/dsf-tools/dsf-tools-build-info-reader/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-tools-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-tools/dsf-tools-bundle-generator/pom.xml b/dsf-tools/dsf-tools-bundle-generator/pom.xml index d0c072133..e02a9594a 100755 --- a/dsf-tools/dsf-tools-bundle-generator/pom.xml +++ b/dsf-tools/dsf-tools-bundle-generator/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-tools-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-tools/dsf-tools-db-migration/pom.xml b/dsf-tools/dsf-tools-db-migration/pom.xml index 5990fcee0..ddb0f7807 100755 --- a/dsf-tools/dsf-tools-db-migration/pom.xml +++ b/dsf-tools/dsf-tools-db-migration/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-tools-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-tools/dsf-tools-docker-secrets-reader/pom.xml b/dsf-tools/dsf-tools-docker-secrets-reader/pom.xml index 068e5cb15..563453c40 100644 --- a/dsf-tools/dsf-tools-docker-secrets-reader/pom.xml +++ b/dsf-tools/dsf-tools-docker-secrets-reader/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-tools-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-tools/dsf-tools-documentation-generator/pom.xml b/dsf-tools/dsf-tools-documentation-generator/pom.xml index b0eef4ae4..70f2a7b50 100644 --- a/dsf-tools/dsf-tools-documentation-generator/pom.xml +++ b/dsf-tools/dsf-tools-documentation-generator/pom.xml @@ -7,7 +7,7 @@ dev.dsf dsf-tools-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-tools/dsf-tools-proxy-test/pom.xml b/dsf-tools/dsf-tools-proxy-test/pom.xml index a6151b8f7..07e0f553c 100755 --- a/dsf-tools/dsf-tools-proxy-test/pom.xml +++ b/dsf-tools/dsf-tools-proxy-test/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-tools-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-tools/dsf-tools-test-data-generator/pom.xml b/dsf-tools/dsf-tools-test-data-generator/pom.xml index bcaaf6325..319ee9e5b 100755 --- a/dsf-tools/dsf-tools-test-data-generator/pom.xml +++ b/dsf-tools/dsf-tools-test-data-generator/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-tools-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/dsf-tools/pom.xml b/dsf-tools/pom.xml index cfca45ad2..c6dd22454 100755 --- a/dsf-tools/pom.xml +++ b/dsf-tools/pom.xml @@ -7,7 +7,7 @@ dev.dsf dsf-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT diff --git a/pom.xml b/pom.xml index 1aedbe243..c2f28f983 100755 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ dev.dsf dsf-pom - 1.5.3-SNAPSHOT + 1.6.0-SNAPSHOT pom From 4b8a60cfa3d11d2ee2d33a921da2cca7ea7a7043 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Wed, 2 Oct 2024 19:43:24 +0200 Subject: [PATCH 06/26] new all_read_access_resources view and improved trigger Added a new all_read_access_resources view that includes all resources except Task and QuestionnaireResponse. Improved after organizations and organization_affiliations insert triggers by removing unnecessary delete/insert operations for FHIR updates (db inserts) of unchanged Organization and OrganizationAffiliation resources. Unchanged in this case means no active status change for both resource types and no role change for OrganizationAffiliations. Both triggers now also use the new all_read_access_resources view. --- .../src/main/resources/db/db.changelog.xml | 2 + .../db/db.read_access.changelog-1.6.0.xml | 72 +++++++++++++++++++ .../on_organization_affiliations_insert.sql | 31 ++++---- .../on_organizations_insert.sql | 57 ++++++++------- 4 files changed, 122 insertions(+), 40 deletions(-) create mode 100644 dsf-fhir/dsf-fhir-server/src/main/resources/db/db.read_access.changelog-1.6.0.xml diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.changelog.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.changelog.xml index 7ab4d051c..90e0f7e40 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.changelog.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.changelog.xml @@ -38,4 +38,6 @@ + + diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.read_access.changelog-1.6.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.read_access.changelog-1.6.0.xml new file mode 100644 index 000000000..a63509673 --- /dev/null +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/db.read_access.changelog-1.6.0.xml @@ -0,0 +1,72 @@ + + + + + + + + + SELECT + id + , version + , type + , resource + FROM ( + SELECT activity_definition_id AS id, version, 'ActivityDefinition'::text AS type, activity_definition AS resource FROM current_activity_definitions + UNION + SELECT binary_id AS id, version, 'Binary'::text AS type, binary_json AS resource FROM current_binaries + UNION + SELECT bundle_id AS id, version, 'Bundle'::text AS type, bundle AS resource FROM current_bundles + UNION + SELECT code_system_id AS id, version, 'CodeSystem'::text AS type, code_system AS resource FROM current_code_systems + UNION + SELECT document_reference_id AS id, version, 'DocumentReference'::text AS type, document_reference AS resource FROM current_document_references + UNION + SELECT endpoint_id AS id, version, 'Endpoint'::text AS type, endpoint AS resource FROM current_endpoints + UNION + SELECT group_id AS id, version, 'Group'::text AS type, group_json AS resource FROM current_groups + UNION + SELECT healthcare_service_id AS id, version, 'HealthcareService'::text AS type, healthcare_service AS resource FROM current_healthcare_services + UNION + SELECT library_id AS id, version, 'Library'::text AS type, library AS resource FROM current_libraries + UNION + SELECT location_id AS id, version, 'Location'::text AS type, location AS resource FROM current_locations + UNION + SELECT measure_report_id AS id, version, 'MeasureReport'::text AS type, measure_report AS resource FROM current_measure_reports + UNION + SELECT measure_id AS id, version, 'Measure'::text AS type, measure AS resource FROM current_measures + UNION + SELECT naming_system_id AS id, version, 'NamingSystem'::text AS type, naming_system AS resource FROM current_naming_systems + UNION + SELECT organization_id AS id, version, 'Organization'::text AS type, organization AS resource FROM current_organizations + UNION + SELECT organization_affiliation_id AS id, version, 'OrganizationAffiliation'::text AS type, organization_affiliation AS resource FROM current_organization_affiliations + UNION + SELECT patient_id AS id, version, 'Patient'::text AS type, patient AS resource FROM current_patients + UNION + SELECT practitioner_role_id AS id, version, 'PractitionerRole'::text AS type, practitioner_role AS resource FROM current_practitioner_roles + UNION + SELECT practitioner_id AS id, version, 'Practitioner'::text AS type, practitioner AS resource FROM current_practitioners + UNION + SELECT provenance_id AS id, version, 'Provenance'::text AS type, provenance AS resource FROM current_provenances + UNION + SELECT questionnaire_id AS id, version, 'Questionnaire'::text AS type, questionnaire AS resource FROM current_questionnaires + UNION + SELECT research_study_id AS id, version, 'ResearchStudy'::text AS type, research_study AS resource FROM current_research_studies + UNION + SELECT structure_definition_id AS id, version, 'StructureDefinition'::text AS type, structure_definition AS resource FROM current_structure_definitions + UNION + SELECT subscription_id AS id, version, 'Subscription'::text AS type, subscription AS resource FROM current_subscriptions + UNION + SELECT value_set_id AS id, version, 'ValueSet'::text AS type, value_set AS resource FROM current_value_sets + ) AS current_all_read_access + + + ALTER TABLE all_read_access_resources OWNER TO ${db.liquibase_user}; + GRANT ALL ON TABLE all_read_access_resources TO ${db.liquibase_user}; + GRANT SELECT ON TABLE all_read_access_resources TO ${db.server_users_group}; + + + \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/trigger_functions/on_organization_affiliations_insert.sql b/dsf-fhir/dsf-fhir-server/src/main/resources/db/trigger_functions/on_organization_affiliations_insert.sql index 5437390a7..80a0d02e3 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/db/trigger_functions/on_organization_affiliations_insert.sql +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/trigger_functions/on_organization_affiliations_insert.sql @@ -1,5 +1,6 @@ CREATE OR REPLACE FUNCTION on_organization_affiliations_insert() RETURNS TRIGGER AS $$ DECLARE + organization_affiliation_exists_active_roles JSONB := (SELECT organization_affiliation->'code' FROM organization_affiliations WHERE organization_affiliation_id = NEW.organization_affiliation_id AND version = NEW.version - 1 AND deleted IS NULL AND organization_affiliation->>'active' = 'true'); reference_regex TEXT := '((http|https):\/\/([A-Za-z0-9\-\\\.\:\%\$]*\/)+)?(Account|ActivityDefinition|AdverseEvent|AllergyIntolerance|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BiologicallyDerivedProduct|BodyStructure|Bundle|CapabilityStatement|CarePlan|CareTeam|CatalogEntry|ChargeItem|ChargeItemDefinition|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition|Consent|Contract|Coverage|CoverageEligibilityRequest|CoverageEligibilityResponse|DetectedIssue|Device|DeviceDefinition|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EffectEvidenceSynthesis|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|EventDefinition|Evidence|EvidenceVariable|ExampleScenario|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingStudy|Immunization|ImmunizationEvaluation|ImmunizationRecommendation|ImplementationGuide|InsurancePlan|Invoice|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationKnowledge|MedicationRequest|MedicationStatement|MedicinalProduct|MedicinalProductAuthorization|MedicinalProductContraindication|MedicinalProductIndication|MedicinalProductIngredient|MedicinalProductInteraction|MedicinalProductManufactured|MedicinalProductPackaged|MedicinalProductPharmaceutical|MedicinalProductUndesirableEffect|MessageDefinition|MessageHeader|MolecularSequence|NamingSystem|NutritionOrder|Observation|ObservationDefinition|OperationDefinition|OperationOutcome|Organization|OrganizationAffiliation|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|Provenance|Questionnaire|QuestionnaireResponse|RelatedPerson|RequestGroup|ResearchDefinition|ResearchElementDefinition|ResearchStudy|ResearchSubject|RiskAssessment|RiskEvidenceSynthesis|Schedule|SearchParameter|ServiceRequest|Slot|Specimen|SpecimenDefinition|StructureDefinition|StructureMap|Subscription|Substance|SubstanceNucleicAcid|SubstancePolymer|SubstanceProtein|SubstanceReferenceInformation|SubstanceSourceMaterial|SubstanceSpecification|SupplyDelivery|SupplyRequest|Task|TerminologyCapabilities|TestReport|TestScript|ValueSet|VerificationResult|VisionPrescription)\/([A-Za-z0-9\-\.]{1,64})(\/_history\/([A-Za-z0-9\-\.]{1,64}))?'; parent_organization_identifier TEXT; member_organization_id UUID; @@ -8,16 +9,22 @@ DECLARE delete_count INT; BEGIN PERFORM on_resources_insert(NEW.organization_affiliation_id, NEW.version, NEW.organization_affiliation); - - DELETE FROM read_access - WHERE access_type = 'ROLE' - AND organization_affiliation_id = NEW.organization_affiliation_id; - GET DIAGNOSTICS delete_count = ROW_COUNT; - RAISE NOTICE 'Existing rows deleted from read_access for created/updated organization-affiliation: %', delete_count; - - RAISE NOTICE 'NEW.organization_affiliation->>''active'' = ''%''', NEW.organization_affiliation->>'active'; - IF (NEW.organization_affiliation->>'active' = 'true') THEN + IF ((NEW.organization_affiliation->>'active' = 'false') AND organization_affiliation_exists_active_roles IS NOT NULL) + OR ((NEW.organization_affiliation->>'active' = 'true') AND organization_affiliation_exists_active_roles IS NOT NULL AND NEW.organization_affiliation->'code' <> organization_affiliation_exists_active_roles) THEN + RAISE NOTICE 'new organization_affiliation inactive and old organization_affiliation exists and active -> delete'; + + DELETE FROM read_access + WHERE access_type = 'ROLE' + AND organization_affiliation_id = NEW.organization_affiliation_id; + + GET DIAGNOSTICS delete_count = ROW_COUNT; + RAISE NOTICE 'Existing rows deleted from read_access for created/updated organization-affiliation: %', delete_count; + + ELSIF ((NEW.organization_affiliation->>'active' = 'true') AND NOT organization_affiliation_exists_active_roles IS NOT NULL) + OR ((NEW.organization_affiliation->>'active' = 'true') AND organization_affiliation_exists_active_roles IS NOT NULL AND NEW.organization_affiliation->'code' <> organization_affiliation_exists_active_roles) THEN + RAISE NOTICE 'new organization_affiliation active and old organization_affiliation not exist or inactive -> insert'; + parent_organization_identifier := jsonb_path_query(organization, '$.identifier[*] ? (@.system == "http://dsf.dev/sid/organization-identifier")')->>'value' FROM current_organizations WHERE organization_id = (regexp_match(NEW.organization_affiliation->'organization'->>'reference', reference_regex))[5]::uuid @@ -43,7 +50,7 @@ BEGIN id , version , resource - FROM all_resources + FROM all_read_access_resources ) AS r ON r.resource->'meta'->'tag' @> ('[{"extension":[{"url":"http://dsf.dev/fhir/StructureDefinition/extension-read-access-parent-organization-role","extension":[{"url":"parent-organization","valueIdentifier":{"system":"http://dsf.dev/sid/organization-identifier","value":"' @@ -66,10 +73,8 @@ BEGIN GET DIAGNOSTICS binary_insert_count = ROW_COUNT; RAISE NOTICE 'Rows inserted into read_access based on Binary.securityContext: %', binary_insert_count; END IF; - - ELSIF (NEW.organization_affiliation->>'active' = 'false') THEN - RAISE NOTICE 'Not inserting any entries to read_access, created/updated organization-affiliation is not active'; END IF; + RETURN NEW; END; $$ LANGUAGE PLPGSQL \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/db/trigger_functions/on_organizations_insert.sql b/dsf-fhir/dsf-fhir-server/src/main/resources/db/trigger_functions/on_organizations_insert.sql index 2eb3218c1..911658f2b 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/db/trigger_functions/on_organizations_insert.sql +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/db/trigger_functions/on_organizations_insert.sql @@ -1,5 +1,6 @@ CREATE OR REPLACE FUNCTION on_organizations_insert() RETURNS TRIGGER AS $$ DECLARE + organization_exists_active BOOLEAN := EXISTS (SELECT 1 FROM organizations WHERE organization_id = NEW.organization_id AND version = NEW.version - 1 AND deleted IS NULL AND organization->>'active' = 'true'); reference_regex TEXT := '((http|https):\/\/([A-Za-z0-9\-\\\.\:\%\$]*\/)+)?(Account|ActivityDefinition|AdverseEvent|AllergyIntolerance|Appointment|AppointmentResponse|AuditEvent|Basic|Binary|BiologicallyDerivedProduct|BodyStructure|Bundle|CapabilityStatement|CarePlan|CareTeam|CatalogEntry|ChargeItem|ChargeItemDefinition|Claim|ClaimResponse|ClinicalImpression|CodeSystem|Communication|CommunicationRequest|CompartmentDefinition|Composition|ConceptMap|Condition|Consent|Contract|Coverage|CoverageEligibilityRequest|CoverageEligibilityResponse|DetectedIssue|Device|DeviceDefinition|DeviceMetric|DeviceRequest|DeviceUseStatement|DiagnosticReport|DocumentManifest|DocumentReference|EffectEvidenceSynthesis|Encounter|Endpoint|EnrollmentRequest|EnrollmentResponse|EpisodeOfCare|EventDefinition|Evidence|EvidenceVariable|ExampleScenario|ExplanationOfBenefit|FamilyMemberHistory|Flag|Goal|GraphDefinition|Group|GuidanceResponse|HealthcareService|ImagingStudy|Immunization|ImmunizationEvaluation|ImmunizationRecommendation|ImplementationGuide|InsurancePlan|Invoice|Library|Linkage|List|Location|Measure|MeasureReport|Media|Medication|MedicationAdministration|MedicationDispense|MedicationKnowledge|MedicationRequest|MedicationStatement|MedicinalProduct|MedicinalProductAuthorization|MedicinalProductContraindication|MedicinalProductIndication|MedicinalProductIngredient|MedicinalProductInteraction|MedicinalProductManufactured|MedicinalProductPackaged|MedicinalProductPharmaceutical|MedicinalProductUndesirableEffect|MessageDefinition|MessageHeader|MolecularSequence|NamingSystem|NutritionOrder|Observation|ObservationDefinition|OperationDefinition|OperationOutcome|Organization|OrganizationAffiliation|Patient|PaymentNotice|PaymentReconciliation|Person|PlanDefinition|Practitioner|PractitionerRole|Procedure|Provenance|Questionnaire|QuestionnaireResponse|RelatedPerson|RequestGroup|ResearchDefinition|ResearchElementDefinition|ResearchStudy|ResearchSubject|RiskAssessment|RiskEvidenceSynthesis|Schedule|SearchParameter|ServiceRequest|Slot|Specimen|SpecimenDefinition|StructureDefinition|StructureMap|Subscription|Substance|SubstanceNucleicAcid|SubstancePolymer|SubstanceProtein|SubstanceReferenceInformation|SubstanceSourceMaterial|SubstanceSpecification|SupplyDelivery|SupplyRequest|Task|TerminologyCapabilities|TestReport|TestScript|ValueSet|VerificationResult|VisionPrescription)\/([A-Za-z0-9\-\.]{1,64})(\/_history\/([A-Za-z0-9\-\.]{1,64}))?'; organization_identifier TEXT := jsonb_path_query(NEW.organization, '$.identifier[*]?(@.system == "http://dsf.dev/sid/organization-identifier")')->>'value'; organization_insert_count INT; @@ -9,36 +10,40 @@ DECLARE roles_delete_count INT; BEGIN PERFORM on_resources_insert(NEW.organization_id, NEW.version, NEW.organization); - - DELETE FROM read_access - WHERE access_type = 'ORGANIZATION' - AND organization_id = NEW.organization_id; - - GET DIAGNOSTICS delete_count = ROW_COUNT; - RAISE NOTICE 'Existing rows deleted from read_access for created/updated organization, ORGANIZATION Tag: %', delete_count; - - DELETE FROM read_access - WHERE access_type = 'ROLE' - AND organization_affiliation_id IN ( - SELECT organization_affiliation_id FROM current_organization_affiliations - WHERE NEW.organization_id = (regexp_match(organization_affiliation->'participatingOrganization'->>'reference', reference_regex))[5]::uuid - OR NEW.organization_id = (regexp_match(organization_affiliation->'organization'->>'reference', reference_regex))[5]::uuid - ); - GET DIAGNOSTICS roles_delete_count = ROW_COUNT; - RAISE NOTICE 'Existing rows deleted from read_access for created/updated organization, ROLE Tag: %', roles_delete_count; - - RAISE NOTICE 'NEW.organization->>''active'' = ''%''', NEW.organization->>'active'; - IF (NEW.organization->>'active' = 'true') THEN + IF (NEW.organization->>'active' = 'false') AND organization_exists_active THEN + RAISE NOTICE 'new organization inactive and old organization exists and active -> delete'; + + DELETE FROM read_access + WHERE access_type = 'ORGANIZATION' + AND organization_id = NEW.organization_id; + + GET DIAGNOSTICS delete_count = ROW_COUNT; + RAISE NOTICE 'Existing rows deleted from read_access for created/updated organization, ORGANIZATION Tag: %', delete_count; + + DELETE FROM read_access + WHERE access_type = 'ROLE' + AND organization_affiliation_id IN ( + SELECT organization_affiliation_id FROM current_organization_affiliations + WHERE NEW.organization_id = (regexp_match(organization_affiliation->'participatingOrganization'->>'reference', reference_regex))[5]::uuid + OR NEW.organization_id = (regexp_match(organization_affiliation->'organization'->>'reference', reference_regex))[5]::uuid + ); + + GET DIAGNOSTICS roles_delete_count = ROW_COUNT; + RAISE NOTICE 'Existing rows deleted from read_access for created/updated organization, ROLE Tag: %', roles_delete_count; + + ELSIF (NEW.organization->>'active' = 'true') AND NOT organization_exists_active THEN + RAISE NOTICE 'new organization active and old organization not exist or inactive -> insert'; + INSERT INTO read_access SELECT id, version, 'ORGANIZATION', NEW.organization_id, NULL - FROM all_resources + FROM all_read_access_resources WHERE jsonb_path_exists(resource,('$.meta.tag[*] ? (@.code == "ORGANIZATION" && @.system == "http://dsf.dev/fhir/CodeSystem/read-access-tag") .extension[*]?(@.url == "http://dsf.dev/fhir/StructureDefinition/extension-read-access-organization") .valueIdentifier[*]?(@.system == "http://dsf.dev/sid/organization-identifier" && @.value == "' || organization_identifier || '")')::jsonpath); - + GET DIAGNOSTICS organization_insert_count = ROW_COUNT; - + WITH temp_role_ids AS ( INSERT INTO read_access SELECT r.id, r.version, 'ROLE', member_organization_id, organization_affiliation_id FROM ( @@ -72,7 +77,7 @@ BEGIN WHERE parent_organization_organization_id = NEW.organization_id OR member_organization_id = NEW.organization_id ) AS oa LEFT JOIN ( - SELECT id, version, resource FROM all_resources + SELECT id, version, resource FROM all_read_access_resources ) AS r ON r.resource->'meta'->'tag' @> ('[{"extension":[{"url":"http://dsf.dev/fhir/StructureDefinition/extension-read-access-parent-organization-role","extension":[{"url":"parent-organization","valueIdentifier":{"system":"http://dsf.dev/sid/organization-identifier","value":"' @@ -101,10 +106,8 @@ BEGIN GET DIAGNOSTICS binary_insert_count = ROW_COUNT; RAISE NOTICE 'Rows inserted into read_access based on Binary.securityContext: %', binary_insert_count; - - ELSIF (NEW.organization->>'active' = 'false') THEN - RAISE NOTICE 'Not inserting any entries to read_access, created/updated organization is not active'; END IF; + RETURN NEW; END; $$ LANGUAGE PLPGSQL \ No newline at end of file From 4f46d8592da31e6fea058e6f61905a747e236ad0 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Wed, 2 Oct 2024 21:10:54 +0200 Subject: [PATCH 07/26] improved constant name --- .../dao/OrganizationAffiliationDaoTest.java | 22 +++++++++---------- .../dev/dsf/fhir/dao/OrganizationDaoTest.java | 22 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java index 3c8b2a14f..19d5a5753 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java @@ -326,7 +326,7 @@ public void testExistsNotDeletedByParentOrganizationMemberOrganizationRoleAndNot private class TaskAsCsvGeneratorReader extends Reader { - public static final int LINE_LENGHT = 1615; + public static final int TASK_ROW_LINE_LENGTH = 1615; private int currentTask; private int maxTasks; @@ -339,23 +339,23 @@ public TaskAsCsvGeneratorReader(int maxTasks) @Override public int read(char[] cbuf, int off, int len) throws IOException { - if (len != LINE_LENGHT) - throw new IllegalArgumentException("Buffer length " + LINE_LENGHT + " expected, not " + len); - if (off % LINE_LENGHT != 0) - throw new IllegalArgumentException("Buffer offset mod " + LINE_LENGHT + " == 0 expected, not " - + (off & LINE_LENGHT) + " (off = " + off + ")"); + if (len != TASK_ROW_LINE_LENGTH) + throw new IllegalArgumentException("Buffer length " + TASK_ROW_LINE_LENGTH + " expected, not " + len); + if (off % TASK_ROW_LINE_LENGTH != 0) + throw new IllegalArgumentException("Buffer offset mod " + TASK_ROW_LINE_LENGTH + " == 0 expected, not " + + (off & TASK_ROW_LINE_LENGTH) + " (off = " + off + ")"); if (currentTask < maxTasks) { String line = generateLine(); - if (len != LINE_LENGHT) - throw new IllegalArgumentException("Buffer length " + LINE_LENGHT + " expected"); + if (len != TASK_ROW_LINE_LENGTH) + throw new IllegalArgumentException("Buffer length " + TASK_ROW_LINE_LENGTH + " expected"); - System.arraycopy(line.toCharArray(), 0, cbuf, 0, LINE_LENGHT); + System.arraycopy(line.toCharArray(), 0, cbuf, 0, TASK_ROW_LINE_LENGTH); currentTask++; - return LINE_LENGHT; + return TASK_ROW_LINE_LENGTH; } else return -1; @@ -414,7 +414,7 @@ public void testBigUpdate() throws Exception CopyManager copyManager = new CopyManager(connection.unwrap(BaseConnection.class)); TaskAsCsvGeneratorReader taskGenerator = new TaskAsCsvGeneratorReader(taskCount); long insertedRows = copyManager.copyIn("COPY tasks FROM STDIN (FORMAT csv)", taskGenerator, - TaskAsCsvGeneratorReader.LINE_LENGHT); + TaskAsCsvGeneratorReader.TASK_ROW_LINE_LENGTH); assertEquals(taskCount, insertedRows); } diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java index e2f065921..dd732de90 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java @@ -259,7 +259,7 @@ public void testUpdateWithExistingBinary() throws Exception private class TaskAsCsvGeneratorReader extends Reader { - public static final int LINE_LENGHT = 1615; + public static final int TASK_ROW_LINE_LENGTH = 1615; private int currentTask; private int maxTasks; @@ -272,23 +272,23 @@ public TaskAsCsvGeneratorReader(int maxTasks) @Override public int read(char[] cbuf, int off, int len) throws IOException { - if (len != LINE_LENGHT) - throw new IllegalArgumentException("Buffer length " + LINE_LENGHT + " expected, not " + len); - if (off % LINE_LENGHT != 0) - throw new IllegalArgumentException("Buffer offset mod " + LINE_LENGHT + " == 0 expected, not " - + (off & LINE_LENGHT) + " (off = " + off + ")"); + if (len != TASK_ROW_LINE_LENGTH) + throw new IllegalArgumentException("Buffer length " + TASK_ROW_LINE_LENGTH + " expected, not " + len); + if (off % TASK_ROW_LINE_LENGTH != 0) + throw new IllegalArgumentException("Buffer offset mod " + TASK_ROW_LINE_LENGTH + " == 0 expected, not " + + (off & TASK_ROW_LINE_LENGTH) + " (off = " + off + ")"); if (currentTask < maxTasks) { String line = generateLine(); - if (len != LINE_LENGHT) - throw new IllegalArgumentException("Buffer length " + LINE_LENGHT + " expected"); + if (len != TASK_ROW_LINE_LENGTH) + throw new IllegalArgumentException("Buffer length " + TASK_ROW_LINE_LENGTH + " expected"); - System.arraycopy(line.toCharArray(), 0, cbuf, 0, LINE_LENGHT); + System.arraycopy(line.toCharArray(), 0, cbuf, 0, TASK_ROW_LINE_LENGTH); currentTask++; - return LINE_LENGHT; + return TASK_ROW_LINE_LENGTH; } else return -1; @@ -327,7 +327,7 @@ public void testBigUpdate() throws Exception CopyManager copyManager = new CopyManager(connection.unwrap(BaseConnection.class)); TaskAsCsvGeneratorReader taskGenerator = new TaskAsCsvGeneratorReader(taskCount); long insertedRows = copyManager.copyIn("COPY tasks FROM STDIN (FORMAT csv)", taskGenerator, - TaskAsCsvGeneratorReader.LINE_LENGHT); + TaskAsCsvGeneratorReader.TASK_ROW_LINE_LENGTH); assertEquals(taskCount, insertedRows); } From 8b12fcb67ab69af7329f55a5dd2b999f636c36bd Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Wed, 2 Oct 2024 21:14:58 +0200 Subject: [PATCH 08/26] fixed length checks (copy/paste error) --- .../java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java | 4 ++-- .../src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java index 19d5a5753..9a0b5e82a 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java @@ -349,8 +349,8 @@ public int read(char[] cbuf, int off, int len) throws IOException { String line = generateLine(); - if (len != TASK_ROW_LINE_LENGTH) - throw new IllegalArgumentException("Buffer length " + TASK_ROW_LINE_LENGTH + " expected"); + if (line.length() != TASK_ROW_LINE_LENGTH) + throw new IllegalArgumentException("Line length " + TASK_ROW_LINE_LENGTH + " expected"); System.arraycopy(line.toCharArray(), 0, cbuf, 0, TASK_ROW_LINE_LENGTH); currentTask++; diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java index dd732de90..608088ec1 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java @@ -282,8 +282,8 @@ public int read(char[] cbuf, int off, int len) throws IOException { String line = generateLine(); - if (len != TASK_ROW_LINE_LENGTH) - throw new IllegalArgumentException("Buffer length " + TASK_ROW_LINE_LENGTH + " expected"); + if (line.length() != TASK_ROW_LINE_LENGTH) + throw new IllegalArgumentException("Line length " + TASK_ROW_LINE_LENGTH + " expected"); System.arraycopy(line.toCharArray(), 0, cbuf, 0, TASK_ROW_LINE_LENGTH); currentTask++; From c61d35d32527eba6deab06fae5bb56721aa369ab Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Wed, 2 Oct 2024 21:17:24 +0200 Subject: [PATCH 09/26] added missing static and final modifiers --- .../java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java | 4 ++-- .../src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java index 9a0b5e82a..7e1e817c7 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationAffiliationDaoTest.java @@ -324,12 +324,12 @@ public void testExistsNotDeletedByParentOrganizationMemberOrganizationRoleAndNot } } - private class TaskAsCsvGeneratorReader extends Reader + private static class TaskAsCsvGeneratorReader extends Reader { public static final int TASK_ROW_LINE_LENGTH = 1615; + private final int maxTasks; private int currentTask; - private int maxTasks; public TaskAsCsvGeneratorReader(int maxTasks) { diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java index 608088ec1..01c2b37f8 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/dao/OrganizationDaoTest.java @@ -257,12 +257,12 @@ public void testUpdateWithExistingBinary() throws Exception dao.update(createdOrg); } - private class TaskAsCsvGeneratorReader extends Reader + private static class TaskAsCsvGeneratorReader extends Reader { public static final int TASK_ROW_LINE_LENGTH = 1615; + private final int maxTasks; private int currentTask; - private int maxTasks; public TaskAsCsvGeneratorReader(int maxTasks) { From 29d5781eab4785fecbbb6cb349a34329de280a11 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Mon, 7 Oct 2024 15:38:25 +0200 Subject: [PATCH 10/26] added missing negation to correct logic error fixes #232 --- .../main/java/dev/dsf/common/config/AbstractJettyConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsf-common/dsf-common-jetty/src/main/java/dev/dsf/common/config/AbstractJettyConfig.java b/dsf-common/dsf-common-jetty/src/main/java/dev/dsf/common/config/AbstractJettyConfig.java index a68f0302f..f401081b5 100644 --- a/dsf-common/dsf-common-jetty/src/main/java/dev/dsf/common/config/AbstractJettyConfig.java +++ b/dsf-common/dsf-common-jetty/src/main/java/dev/dsf/common/config/AbstractJettyConfig.java @@ -429,7 +429,7 @@ private Duration oidcClientConnectTimeout() private Proxy oidcClientProxy() { ProxyConfig config = new ProxyConfigImpl(proxyUrl, proxyUsername, proxyPassword, proxyNoProxy); - if (config.getUrl() != null && config.isNoProxyUrl(oidcProviderRealmBaseUrl)) + if (config.getUrl() != null && !config.isNoProxyUrl(oidcProviderRealmBaseUrl)) { try { From 54b5a3a8670e73e49e621062e266446029c75566 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Mon, 7 Oct 2024 17:16:09 +0200 Subject: [PATCH 11/26] nginx config cleanup and version upgrade --- .../docker-compose.yml | 2 +- .../proxy/conf.d/default.conf | 46 ------------------- .../proxy/nginx.conf | 21 +-------- 3 files changed, 2 insertions(+), 67 deletions(-) delete mode 100644 dsf-docker-test-setup-3dic-ttp/proxy/conf.d/default.conf diff --git a/dsf-docker-test-setup-3dic-ttp/docker-compose.yml b/dsf-docker-test-setup-3dic-ttp/docker-compose.yml index 3fd3bd014..440701125 100644 --- a/dsf-docker-test-setup-3dic-ttp/docker-compose.yml +++ b/dsf-docker-test-setup-3dic-ttp/docker-compose.yml @@ -1,7 +1,7 @@ version: '3.8' services: proxy: - image: nginx:1.23 + image: nginx:1.27 restart: "no" ports: - 127.0.0.1:443:443 diff --git a/dsf-docker-test-setup-3dic-ttp/proxy/conf.d/default.conf b/dsf-docker-test-setup-3dic-ttp/proxy/conf.d/default.conf deleted file mode 100644 index b460be080..000000000 --- a/dsf-docker-test-setup-3dic-ttp/proxy/conf.d/default.conf +++ /dev/null @@ -1,46 +0,0 @@ -server { - listen 80; - listen [::]:80; - server_name localhost; - - #charset koi8-r; - #access_log /var/log/nginx/host.access.log main; - - location / { - root /usr/share/nginx/html; - index index.html index.htm; - } - - #error_page 404 /404.html; - - # redirect server error pages to the static page /50x.html - # - error_page 500 502 503 504 /50x.html; - location = /50x.html { - root /usr/share/nginx/html; - } - - # proxy the PHP scripts to Apache listening on 127.0.0.1:80 - # - #location ~ \.php$ { - # proxy_pass http://127.0.0.1; - #} - - # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 - # - #location ~ \.php$ { - # root html; - # fastcgi_pass 127.0.0.1:9000; - # fastcgi_index index.php; - # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; - # include fastcgi_params; - #} - - # deny access to .htaccess files, if Apache's document root - # concurs with nginx's one - # - #location ~ /\.ht { - # deny all; - #} -} - diff --git a/dsf-docker-test-setup-3dic-ttp/proxy/nginx.conf b/dsf-docker-test-setup-3dic-ttp/proxy/nginx.conf index 04ee80c96..d9aece023 100644 --- a/dsf-docker-test-setup-3dic-ttp/proxy/nginx.conf +++ b/dsf-docker-test-setup-3dic-ttp/proxy/nginx.conf @@ -1,16 +1,6 @@ - -user nginx; -worker_processes 1; - -error_log /var/log/nginx/error.log warn; -pid /var/run/nginx.pid; - - events { - worker_connections 1024; } - http { include /etc/nginx/mime.types; default_type application/octet-stream; @@ -19,15 +9,6 @@ http { '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; - access_log /var/log/nginx/access.log main; - - sendfile on; - #tcp_nopush on; - - keepalive_timeout 65; - - #gzip on; - ssl_certificate /run/secrets/proxy_certificate_and_int_cas.pem; ssl_certificate_key /run/secrets/proxy_certificate_private_key.pem; ssl_protocols TLSv1.2 TLSv1.3; @@ -45,4 +26,4 @@ http { } include /etc/nginx/conf.d/*.conf; -} +} \ No newline at end of file From b2072d82f485ffb13dd619318c2cce82c1bcde06 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Mon, 7 Oct 2024 17:20:03 +0200 Subject: [PATCH 12/26] forward proxy image and service, proxy configured for dic1-bpe keycloak excluded from forward proxy, works with fix from PR #234 --- .../docker-compose.yml | 16 ++++++++++++++++ .../forward-proxy/Dockerfile | 4 ++++ .../forward-proxy/tinyproxy.conf | 6 ++++++ 3 files changed, 26 insertions(+) create mode 100644 dsf-docker-test-setup-3dic-ttp/forward-proxy/Dockerfile create mode 100644 dsf-docker-test-setup-3dic-ttp/forward-proxy/tinyproxy.conf diff --git a/dsf-docker-test-setup-3dic-ttp/docker-compose.yml b/dsf-docker-test-setup-3dic-ttp/docker-compose.yml index 440701125..5895c6bd5 100644 --- a/dsf-docker-test-setup-3dic-ttp/docker-compose.yml +++ b/dsf-docker-test-setup-3dic-ttp/docker-compose.yml @@ -106,6 +106,15 @@ services: --spi-truststore-file-password=password --spi-truststore-file-hostname-verification-policy=STRICT + forward-proxy: + build: ./forward-proxy + restart: "no" + environment: + TZ: Europe/Berlin + networks: + forward-proxy: + internet: + dic1-fhir: build: ../dsf-fhir/dsf-fhir-server-jetty/docker image: datasharingframework/fhir @@ -518,15 +527,21 @@ services: DEV_DSF_SERVER_AUTH_OIDC_PROVIDER_CLIENT_TRUST_SERVER_CERTIFICATE_CAS: /run/secrets/app_server_trust_certificates.pem DEV_DSF_SERVER_AUTH_OIDC_CLIENT_ID: dic1-bpe DEV_DSF_SERVER_AUTH_OIDC_CLIENT_SECRET: ytqFCErw9GfhVUrrM8xc0Grbu4r7qGig + DEV_DSF_PROXY_URL: http://forward-proxy:8080 + DEV_DSF_PROXY_USERNAME: proxy_user + DEV_DSF_PROXY_PASSWORD: proxy_password + DEV_DSF_PROXY_NOPROXY: keycloak networks: dic1-bpe-frontend: ipv4_address: 172.20.0.35 dic1-bpe-backend: internet: + forward-proxy: depends_on: - db - dic1-fhir - keycloak + - forward-proxy dic2-bpe: build: ../dsf-bpe/dsf-bpe-server-jetty/docker @@ -944,6 +959,7 @@ networks: - subnet: 172.20.0.56/29 ttp-bpe-backend: internet: + forward-proxy: volumes: db-data: diff --git a/dsf-docker-test-setup-3dic-ttp/forward-proxy/Dockerfile b/dsf-docker-test-setup-3dic-ttp/forward-proxy/Dockerfile new file mode 100644 index 000000000..bd4f3af20 --- /dev/null +++ b/dsf-docker-test-setup-3dic-ttp/forward-proxy/Dockerfile @@ -0,0 +1,4 @@ +FROM alpine:3.20 +RUN apk add --no-cache tinyproxy +COPY tinyproxy.conf /etc/tinyproxy/tinyproxy.conf +CMD ["tinyproxy", "-d"] \ No newline at end of file diff --git a/dsf-docker-test-setup-3dic-ttp/forward-proxy/tinyproxy.conf b/dsf-docker-test-setup-3dic-ttp/forward-proxy/tinyproxy.conf new file mode 100644 index 000000000..e08799ca1 --- /dev/null +++ b/dsf-docker-test-setup-3dic-ttp/forward-proxy/tinyproxy.conf @@ -0,0 +1,6 @@ +User tinyproxy +Group tinyproxy +Port 8080 +Timeout 100 +LogLevel Connect +BasicAuth proxy_user proxy_password \ No newline at end of file From ef240cb6c542d79d602c368b0e50f948231d4bc5 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Mon, 7 Oct 2024 17:30:49 +0200 Subject: [PATCH 13/26] code cleanup --- .../main/java/dev/dsf/bpe/subscription/FhirConnectorImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/subscription/FhirConnectorImpl.java b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/subscription/FhirConnectorImpl.java index d53a85f7d..c61265a20 100644 --- a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/subscription/FhirConnectorImpl.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/subscription/FhirConnectorImpl.java @@ -228,7 +228,7 @@ private void connectWebsocket(Subscription subscription) { try { - WebsocketClient client = clientProvider.getLocalWebsocketClient(() -> connect(), + WebsocketClient client = clientProvider.getLocalWebsocketClient(this::connect, subscription.getIdElement().getIdPart()); EventType eventType = toEventType(subscription.getChannel().getPayload()); @@ -260,7 +260,7 @@ private Void onError(Throwable t) { // no debug log, exception previously logged by retrieveWebsocketSubscription, loadNewResources and // connectWebsocket methods - logger.error("Error while loading existing {} resources and connecting websocket: {} - {}", resourceName, + logger.error("Error loading existing {} resources and connecting websocket: {} - {}", resourceName, t.getClass().getName(), t.getMessage()); return null; From 5ee060bf5eaf781077068ba5bb8537b55762f7a8 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Mon, 7 Oct 2024 17:36:13 +0200 Subject: [PATCH 14/26] enables reconnect including REST GET for abnormally closed websockets Enables the use of the re-connector code for abnormally closed websocket connections. The (re-)connector searches for Subscription resources, downloads existing Task and QuestionnaireResponse resources before establishing the Task and QuestionnaireResponse websocket connections. Fixes #233 --- .../src/main/java/dev/dsf/fhir/client/ClientEndpoint.java | 4 +++- .../main/java/dev/dsf/fhir/client/WebsocketClientTyrus.java | 6 ++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/dsf-fhir/dsf-fhir-websocket-client/src/main/java/dev/dsf/fhir/client/ClientEndpoint.java b/dsf-fhir/dsf-fhir-websocket-client/src/main/java/dev/dsf/fhir/client/ClientEndpoint.java index 9283afe33..842548613 100755 --- a/dsf-fhir/dsf-fhir-websocket-client/src/main/java/dev/dsf/fhir/client/ClientEndpoint.java +++ b/dsf-fhir/dsf-fhir-websocket-client/src/main/java/dev/dsf/fhir/client/ClientEndpoint.java @@ -1,5 +1,6 @@ package dev.dsf.fhir.client; +import java.util.EnumSet; import java.util.function.Consumer; import java.util.function.Supplier; @@ -80,7 +81,8 @@ public void onClose(Session session, CloseReason closeReason) logger.warn("Websocket closed, session {}: {} - {}", session.getId(), closeReason.getCloseCode().getCode(), closeReason.getReasonPhrase()); - if (CloseReason.CloseCodes.CANNOT_ACCEPT.equals(closeReason.getCloseCode())) + if (EnumSet.of(CloseReason.CloseCodes.CANNOT_ACCEPT, CloseReason.CloseCodes.CLOSED_ABNORMALLY) + .contains(closeReason.getCloseCode())) { logger.info("Trying to reconnect websocket"); reconnector.run(); diff --git a/dsf-fhir/dsf-fhir-websocket-client/src/main/java/dev/dsf/fhir/client/WebsocketClientTyrus.java b/dsf-fhir/dsf-fhir-websocket-client/src/main/java/dev/dsf/fhir/client/WebsocketClientTyrus.java index 04165f981..40fe3f13f 100755 --- a/dsf-fhir/dsf-fhir-websocket-client/src/main/java/dev/dsf/fhir/client/WebsocketClientTyrus.java +++ b/dsf-fhir/dsf-fhir-websocket-client/src/main/java/dev/dsf/fhir/client/WebsocketClientTyrus.java @@ -90,8 +90,8 @@ public boolean onDisconnect(CloseReason closeReason) private final String userAgentValue; private final ClientEndpoint endpoint; - private ClientManager manager; - private Session connection; + private volatile ClientManager manager; + private volatile Session connection; private volatile boolean closed; public WebsocketClientTyrus(Runnable reconnector, URI wsUri, KeyStore trustStore, KeyStore keyStore, @@ -131,6 +131,8 @@ public void connect() if (manager != null) throw new IllegalStateException("Allready connecting/connected"); + closed = false; + manager = ClientManager.createClient(); manager.getProperties().put(ClientProperties.RECONNECT_HANDLER, reconnectHandler); manager.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, new SslEngineConfigurator(sslContext)); From bc48b41fc09d7529f62c34eb5c254718d229fc71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hringer?= Date: Thu, 5 Sep 2024 15:55:33 +0200 Subject: [PATCH 15/26] Added integration test for posting a Questionnaire and a corresponding QuestionnaireResponse resource at the same time in one transaction Bundle --- ...sQuestionnaireResponseIntegrationTest.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java index bde13972b..f74384e9b 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java @@ -3,12 +3,16 @@ import static org.junit.Assert.assertNotNull; import java.util.Optional; +import java.util.UUID; +import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Questionnaire; import org.hl7.fhir.r4.model.QuestionnaireResponse; +import org.hl7.fhir.r4.model.ResourceType; import org.hl7.fhir.r4.model.StringType; import org.junit.Test; +import dev.dsf.fhir.dao.BundleDao; import dev.dsf.fhir.dao.QuestionnaireDao; public class QuestionnaireVsQuestionnaireResponseIntegrationTest extends AbstractQuestionnaireIntegrationTest @@ -146,4 +150,50 @@ public void testQuestionnaireResponseValidatesAgainstQuestionnaireProfileVersion assertNotNull(updatedQr.getIdElement().getIdPart()); assertNotNull(updatedQr.getIdElement().getVersionIdPart()); } + + @Test + public void testPostQuestionnaireAndCorrespondingQuestionnaireResponseInTransactionBundleOrderQuestionnaireBeforeQuestionnaireResponse() + throws Exception + { + Questionnaire questionnaire = createQuestionnaireProfileVersion150("1.5.3"); + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("1.5.3"); + + Bundle bundle = new Bundle(); + bundle.setId("urn:uuid:" + UUID.randomUUID()); + bundle.setType(Bundle.BundleType.TRANSACTION); + questionnaire.setId("urn:uuid:" + UUID.randomUUID()); + bundle.addEntry().setResource(questionnaire).setFullUrl("urn:uuid:" + questionnaire.getId()).getRequest() + .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.Questionnaire.name()); + questionnaireResponse.setId("urn:uuid:" + UUID.randomUUID()); + bundle.addEntry().setResource(questionnaireResponse).setFullUrl("urn:uuid:" + questionnaireResponse.getId()) + .getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.QuestionnaireResponse.name()); + + BundleDao bundleDao = getSpringWebApplicationContext().getBean(BundleDao.class); + bundleDao.create(bundle); + + assertNotNull(getWebserviceClient().postBundle(bundle)); + } + + @Test + public void testPostQuestionnaireAndCorrespondingQuestionnaireResponseInTransactionBundleOrderQuestionnaireResponseBeforeQuestionnaire() + throws Exception + { + Questionnaire questionnaire = createQuestionnaireProfileVersion150("1.5.3"); + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("1.5.3"); + + Bundle bundle = new Bundle(); + bundle.setId("urn:uuid:" + UUID.randomUUID()); + bundle.setType(Bundle.BundleType.TRANSACTION); + questionnaire.setId("urn:uuid:" + UUID.randomUUID()); + questionnaireResponse.setId("urn:uuid:" + UUID.randomUUID()); + bundle.addEntry().setResource(questionnaireResponse).setFullUrl("urn:uuid:" + questionnaireResponse.getId()) + .getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.QuestionnaireResponse.name()); + bundle.addEntry().setResource(questionnaire).setFullUrl("urn:uuid:" + questionnaire.getId()).getRequest() + .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.Questionnaire.name()); + + BundleDao bundleDao = getSpringWebApplicationContext().getBean(BundleDao.class); + bundleDao.create(bundle); + + assertNotNull(getWebserviceClient().postBundle(bundle)); + } } \ No newline at end of file From 468d460af92d2cb7f408d8a833084e39971bbbd8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hringer?= Date: Thu, 5 Sep 2024 16:37:32 +0200 Subject: [PATCH 16/26] No idea why I needed those in the first place --- ...QuestionnaireVsQuestionnaireResponseIntegrationTest.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java index f74384e9b..7c35a11ec 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java @@ -168,9 +168,6 @@ public void testPostQuestionnaireAndCorrespondingQuestionnaireResponseInTransact bundle.addEntry().setResource(questionnaireResponse).setFullUrl("urn:uuid:" + questionnaireResponse.getId()) .getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.QuestionnaireResponse.name()); - BundleDao bundleDao = getSpringWebApplicationContext().getBean(BundleDao.class); - bundleDao.create(bundle); - assertNotNull(getWebserviceClient().postBundle(bundle)); } @@ -191,9 +188,6 @@ public void testPostQuestionnaireAndCorrespondingQuestionnaireResponseInTransact bundle.addEntry().setResource(questionnaire).setFullUrl("urn:uuid:" + questionnaire.getId()).getRequest() .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.Questionnaire.name()); - BundleDao bundleDao = getSpringWebApplicationContext().getBean(BundleDao.class); - bundleDao.create(bundle); - assertNotNull(getWebserviceClient().postBundle(bundle)); } } \ No newline at end of file From 76cda1b3dbec3adc38d4aa99556e13e481261707 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hringer?= Date: Thu, 5 Sep 2024 17:22:38 +0200 Subject: [PATCH 17/26] Asserts all resource have been created --- ...estionnaireVsQuestionnaireResponseIntegrationTest.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java index 7c35a11ec..b2d88268b 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java @@ -1,7 +1,9 @@ package dev.dsf.fhir.integration; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -168,7 +170,8 @@ public void testPostQuestionnaireAndCorrespondingQuestionnaireResponseInTransact bundle.addEntry().setResource(questionnaireResponse).setFullUrl("urn:uuid:" + questionnaireResponse.getId()) .getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.QuestionnaireResponse.name()); - assertNotNull(getWebserviceClient().postBundle(bundle)); + assertTrue(getWebserviceClient().postBundle(bundle).getEntry().stream() + .allMatch(entry -> entry.getResponse().getStatus().equals("201 Created"))); } @Test @@ -188,6 +191,7 @@ public void testPostQuestionnaireAndCorrespondingQuestionnaireResponseInTransact bundle.addEntry().setResource(questionnaire).setFullUrl("urn:uuid:" + questionnaire.getId()).getRequest() .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.Questionnaire.name()); - assertNotNull(getWebserviceClient().postBundle(bundle)); + assertTrue(getWebserviceClient().postBundle(bundle).getEntry().stream() + .allMatch(entry -> entry.getResponse().getStatus().equals("201 Created"))); } } \ No newline at end of file From 361d3607e21407aa450106656b802ade27bde54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20B=C3=B6hringer?= Date: Fri, 6 Sep 2024 10:49:37 +0200 Subject: [PATCH 18/26] Removed setting resource id's unnecessarily. Removed unused imports. --- ...reVsQuestionnaireResponseIntegrationTest.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java index b2d88268b..38c010c1f 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java @@ -3,7 +3,6 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; -import java.util.Objects; import java.util.Optional; import java.util.UUID; @@ -14,7 +13,6 @@ import org.hl7.fhir.r4.model.StringType; import org.junit.Test; -import dev.dsf.fhir.dao.BundleDao; import dev.dsf.fhir.dao.QuestionnaireDao; public class QuestionnaireVsQuestionnaireResponseIntegrationTest extends AbstractQuestionnaireIntegrationTest @@ -161,13 +159,10 @@ public void testPostQuestionnaireAndCorrespondingQuestionnaireResponseInTransact QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("1.5.3"); Bundle bundle = new Bundle(); - bundle.setId("urn:uuid:" + UUID.randomUUID()); bundle.setType(Bundle.BundleType.TRANSACTION); - questionnaire.setId("urn:uuid:" + UUID.randomUUID()); - bundle.addEntry().setResource(questionnaire).setFullUrl("urn:uuid:" + questionnaire.getId()).getRequest() + bundle.addEntry().setResource(questionnaire).setFullUrl("urn:uuid:" + UUID.randomUUID().toString()).getRequest() .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.Questionnaire.name()); - questionnaireResponse.setId("urn:uuid:" + UUID.randomUUID()); - bundle.addEntry().setResource(questionnaireResponse).setFullUrl("urn:uuid:" + questionnaireResponse.getId()) + bundle.addEntry().setResource(questionnaireResponse).setFullUrl("urn:uuid:" + UUID.randomUUID().toString()) .getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.QuestionnaireResponse.name()); assertTrue(getWebserviceClient().postBundle(bundle).getEntry().stream() @@ -182,13 +177,10 @@ public void testPostQuestionnaireAndCorrespondingQuestionnaireResponseInTransact QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("1.5.3"); Bundle bundle = new Bundle(); - bundle.setId("urn:uuid:" + UUID.randomUUID()); bundle.setType(Bundle.BundleType.TRANSACTION); - questionnaire.setId("urn:uuid:" + UUID.randomUUID()); - questionnaireResponse.setId("urn:uuid:" + UUID.randomUUID()); - bundle.addEntry().setResource(questionnaireResponse).setFullUrl("urn:uuid:" + questionnaireResponse.getId()) + bundle.addEntry().setResource(questionnaireResponse).setFullUrl("urn:uuid:" + UUID.randomUUID().toString()) .getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.QuestionnaireResponse.name()); - bundle.addEntry().setResource(questionnaire).setFullUrl("urn:uuid:" + questionnaire.getId()).getRequest() + bundle.addEntry().setResource(questionnaire).setFullUrl("urn:uuid:" + UUID.randomUUID().toString()).getRequest() .setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.Questionnaire.name()); assertTrue(getWebserviceClient().postBundle(bundle).getEntry().stream() From 2650244b4f00dbc3afa695aeb32fc0d5a315d5a7 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Mon, 9 Sep 2024 12:50:30 +0200 Subject: [PATCH 19/26] partial fix for #226 Enables creation of Questionnaire and QuestionnaireResponse in a transaction Bundle if order is Questionnaire before QuestionnaireResponse. --- .../QuestionnaireResponseAuthorizationRule.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java index e0fb25748..dd3b3273f 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java @@ -50,7 +50,8 @@ public Optional reasonCreateAllowed(Connection connection, Identity iden { if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.CREATE)) { - Optional errors = newResourceOk(newResource, EnumSet.of(QuestionnaireResponseStatus.INPROGRESS)); + Optional errors = newResourceOk(connection, newResource, + EnumSet.of(QuestionnaireResponseStatus.INPROGRESS)); if (errors.isEmpty()) { // TODO implement unique criteria based on UserTask.id when implemented as identifier @@ -70,7 +71,7 @@ public Optional reasonCreateAllowed(Connection connection, Identity iden } } - private Optional newResourceOk(QuestionnaireResponse newResource, + private Optional newResourceOk(Connection connection, QuestionnaireResponse newResource, EnumSet allowedStatus) { List errors = new ArrayList<>(); @@ -90,7 +91,7 @@ private Optional newResourceOk(QuestionnaireResponse newResource, getItemAndValidate(newResource, CODESYSTEM_DSF_BPMN_USER_TASK_VALUE_USER_TASK_ID, errors); String questionnaireUrlAndVersion = newResource.getQuestionnaire(); - if (!questionnaireExists(questionnaireUrlAndVersion)) + if (!questionnaireExists(connection, questionnaireUrlAndVersion)) { errors.add( "Questionnaire ressource referenced via canonical QuestionnaireResponse.questionnaire does not exist"); @@ -149,12 +150,12 @@ private Optional getItemAndValidate(QuestionnaireResponse newResource, S return Optional.of(value.getValue()); } - private boolean questionnaireExists(String questionnaireUrlAndVersion) + private boolean questionnaireExists(Connection connection, String questionnaireUrlAndVersion) { try { Optional questionnaire = daoProvider.getQuestionnaireDao() - .readByUrlAndVersion(questionnaireUrlAndVersion); + .readByUrlAndVersionWithTransaction(connection, questionnaireUrlAndVersion); return questionnaire.isPresent(); } @@ -188,7 +189,7 @@ public Optional reasonUpdateAllowed(Connection connection, Identity iden { if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.UPDATE)) { - Optional errors = newResourceOk(newResource, + Optional errors = newResourceOk(connection, newResource, EnumSet.of(QuestionnaireResponseStatus.COMPLETED, QuestionnaireResponseStatus.STOPPED)); if (errors.isEmpty()) { From 0094c2a5a9a5c256b16e75ea25f3b67111b49a12 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Mon, 30 Sep 2024 17:39:42 +0200 Subject: [PATCH 20/26] moved questionnaire canonical reference check, code cleanup, more tests ReferenceExtractorImpl now also extracts canonical references. Moved the QuestionnaireResponse.qestionnaire canonical reference check from QuestionnaireResponseAuthorizationRule to the general reference check infrastructure, enabling creation of Questionnaire and QuestionnaireResponse resources in the same transaction bundle regardless of order. Currently only Task.instantiatesCanonical and QuestionnaireResponse.qestionnaire canonical references are enforced. --- .../fhir/service/ReferenceExtractorImpl.java | 122 ++++++++++--- .../dsf/fhir/service/ResourceReference.java | 51 ++++-- .../AbstractAuthorizationRule.java | 6 - ...uestionnaireResponseAuthorizationRule.java | 27 +-- .../dao/command/ReferencesHelperImpl.java | 5 +- .../dsf/fhir/service/ReferenceResolver.java | 45 ++++- .../fhir/service/ReferenceResolverImpl.java | 162 ++++++++++-------- .../impl/AbstractResourceServiceImpl.java | 5 +- .../QuestionnaireResponseIntegrationTest.java | 10 +- ...sQuestionnaireResponseIntegrationTest.java | 13 ++ 10 files changed, 295 insertions(+), 151 deletions(-) diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/dev/dsf/fhir/service/ReferenceExtractorImpl.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/dev/dsf/fhir/service/ReferenceExtractorImpl.java index 9af14321d..d6dc077a9 100644 --- a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/dev/dsf/fhir/service/ReferenceExtractorImpl.java +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/dev/dsf/fhir/service/ReferenceExtractorImpl.java @@ -10,6 +10,7 @@ import org.hl7.fhir.r4.model.Attachment; import org.hl7.fhir.r4.model.BackboneElement; import org.hl7.fhir.r4.model.Binary; +import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.CarePlan; import org.hl7.fhir.r4.model.CareTeam; import org.hl7.fhir.r4.model.ClaimResponse; @@ -80,18 +81,25 @@ public class ReferenceExtractorImpl implements ReferenceExtractor private Function toResourceReferenceFromReference(String referenceLocation, Class... referenceTypes) { - return ref -> new ResourceReference(referenceLocation, ref, referenceTypes); + return reference -> new ResourceReference(referenceLocation, reference, referenceTypes); } private Function toResourceReferenceFromRelatedArtifact( String relatedArtifactLocation) { - return rel -> new ResourceReference(relatedArtifactLocation, rel); + return relatedArtifact -> new ResourceReference(relatedArtifactLocation, relatedArtifact); } private Function toResourceReferenceFromAttachment(String attachmentLocation) { - return rel -> new ResourceReference(attachmentLocation, rel); + return attachment -> new ResourceReference(attachmentLocation, attachment); + } + + @SafeVarargs + private Function toResourceReferenceFromCanonical(String canonicalLocation, + Class... referenceTypes) + { + return canonical -> new ResourceReference(canonicalLocation, canonical, referenceTypes); } @SafeVarargs @@ -260,6 +268,50 @@ private Stream getReferences(E ba .map(toResourceReferenceFromReference(referenceLocation, referenceTypes)) : Stream.empty(); } + @SafeVarargs + private Stream getCanonical(R resource, Predicate hasCanonical, + Function getCanonical, String canonicalLocation, + Class... canonicalTypes) + { + return hasCanonical.test(resource) ? Stream.of(getCanonical.apply(resource)) + .map(toResourceReferenceFromCanonical(canonicalLocation, canonicalTypes)) : Stream.empty(); + } + + @SafeVarargs + private Stream getCanonicals(R resource, Predicate hasCanonical, + Function> getCanonicals, String canonicalLocation, + Class... canonicalTypes) + { + return hasCanonical.test(resource) ? Stream.of(getCanonicals.apply(resource)).flatMap(List::stream) + .map(toResourceReferenceFromCanonical(canonicalLocation, canonicalTypes)) : Stream.empty(); + } + + @SafeVarargs + private Stream getCanonical(E backboneElement, + Predicate hasCanonical, Function getCanonical, String canonicalLocation, + Class... canonicalTypes) + { + return hasCanonical.test(backboneElement) ? Stream.of(getCanonical.apply(backboneElement)) + .map(toResourceReferenceFromCanonical(canonicalLocation, canonicalTypes)) : Stream.empty(); + } + + @SafeVarargs + private Stream getBackboneElementsCanonical( + R resource, Predicate hasBackboneElements, Function> getBackboneElements, + Predicate hasCanonical, Function getCanonical, String canonicalLocation, + Class... canonicalTypes) + { + if (hasBackboneElements.test(resource)) + { + List backboneElements = getBackboneElements.apply(resource); + return backboneElements.stream() + .map(e -> getCanonical(e, hasCanonical, getCanonical, canonicalLocation, canonicalTypes)) + .flatMap(Function.identity()); + } + else + return Stream.empty(); + } + private Stream getExtensionReferences(DomainResource resource) { var extensions = resource.getExtension().stream().filter(e -> e.getValue() instanceof Reference) @@ -447,9 +499,14 @@ public Stream getReferences(CodeSystem resource) if (resource == null) return Stream.empty(); + var supplements = getCanonical(resource, CodeSystem::hasSupplementsElement, CodeSystem::getSupplementsElement, + "CodeSystem.supplements", CodeSystem.class); + var valueSet = getCanonical(resource, CodeSystem::hasValueSetElement, CodeSystem::getValueSetElement, + "CodeSystem.valueSet", ValueSet.class); + var extensionReferences = getExtensionReferences(resource); - return extensionReferences; + return concat(valueSet, supplements, extensionReferences); } @Override @@ -588,6 +645,8 @@ public Stream getReferences(Measure resource) if (resource == null) return Stream.empty(); + var library = getCanonicals(resource, Measure::hasLibrary, Measure::getLibrary, "Measure.library", + Library.class); var subject = getReference(resource, Measure::hasSubjectReference, Measure::getSubjectReference, "Measure.subject", Group.class); var relatedArtifacts = getRelatedArtifacts(resource, Measure::hasRelatedArtifact, Measure::getRelatedArtifact, @@ -595,7 +654,7 @@ public Stream getReferences(Measure resource) var extensionReferences = getExtensionReferences(resource); - return concat(subject, relatedArtifacts, extensionReferences); + return concat(library, subject, relatedArtifacts, extensionReferences); } @Override @@ -604,6 +663,8 @@ public Stream getReferences(MeasureReport resource) if (resource == null) return Stream.empty(); + var measure = getCanonical(resource, MeasureReport::hasMeasureElement, MeasureReport::getMeasureElement, + "MeasureReport.measure", Measure.class); var subject = getReference(resource, MeasureReport::hasSubject, MeasureReport::getSubject, "MeasureReport.subject", Patient.class, Practitioner.class, PractitionerRole.class, Location.class, Device.class, RelatedPerson.class, Group.class); @@ -627,7 +688,8 @@ public Stream getReferences(MeasureReport resource) var extensionReferences = getExtensionReferences(resource); - return concat(subject, reporter, subjectResults1, subjectResults2, evaluatedResource, extensionReferences); + return concat(measure, subject, reporter, subjectResults1, subjectResults2, evaluatedResource, + extensionReferences); } @Override @@ -785,20 +847,24 @@ public Stream getReferences(Questionnaire resource) if (resource == null) return Stream.empty(); + var derivedFrom = getCanonicals(resource, Questionnaire::hasDerivedFrom, Questionnaire::getDerivedFrom, + "Questionnaire.derivedFrom", Questionnaire.class); var enableWhen = getBackboneElements2Reference(resource, Questionnaire::hasItem, Questionnaire::getItem, Questionnaire.QuestionnaireItemComponent::hasEnableWhen, Questionnaire.QuestionnaireItemComponent::getEnableWhen, Questionnaire.QuestionnaireItemEnableWhenComponent::hasAnswerReference, Questionnaire.QuestionnaireItemEnableWhenComponent::getAnswerReference, "Questionnaire.item.enableWhen.answerReference"); - var answerOption = getBackboneElements2Reference(resource, Questionnaire::hasItem, Questionnaire::getItem, Questionnaire.QuestionnaireItemComponent::hasAnswerOption, Questionnaire.QuestionnaireItemComponent::getAnswerOption, Questionnaire.QuestionnaireItemAnswerOptionComponent::hasValueReference, Questionnaire.QuestionnaireItemAnswerOptionComponent::getValueReference, "Questionnaire.item.answerOption.valueReference"); - + var answerValueSet = getBackboneElementsCanonical(resource, Questionnaire::hasItem, Questionnaire::getItem, + Questionnaire.QuestionnaireItemComponent::hasAnswerValueSetElement, + Questionnaire.QuestionnaireItemComponent::getAnswerValueSetElement, "Questionnaire.item.answerValueSet", + ValueSet.class); var initial = getBackboneElements2Reference(resource, Questionnaire::hasItem, Questionnaire::getItem, Questionnaire.QuestionnaireItemComponent::hasInitial, Questionnaire.QuestionnaireItemComponent::getInitial, @@ -808,7 +874,7 @@ public Stream getReferences(Questionnaire resource) var extensionReferences = getExtensionReferences(resource); - return concat(enableWhen, answerOption, initial, extensionReferences); + return concat(derivedFrom, enableWhen, answerOption, answerValueSet, initial, extensionReferences); } @Override @@ -820,26 +886,24 @@ public Stream getReferences(QuestionnaireResponse resource) var author = getReference(resource, QuestionnaireResponse::hasAuthor, QuestionnaireResponse::getAuthor, "QuestionnaireResponse.author", Device.class, Organization.class, Patient.class, Practitioner.class, PractitionerRole.class, RelatedPerson.class); - var basedOn = getReferences(resource, QuestionnaireResponse::hasBasedOn, QuestionnaireResponse::getBasedOn, "QuestionnaireResponse.basedOn", CarePlan.class, ServiceRequest.class); - var encounter = getReference(resource, QuestionnaireResponse::hasEncounter, QuestionnaireResponse::getEncounter, "QuestionnaireResponse.encounter", Encounter.class); - var partOf = getReferences(resource, QuestionnaireResponse::hasPartOf, QuestionnaireResponse::getPartOf, "QuestionnaireResponse.partOf", Observation.class, Procedure.class); - + var questionnaire = getCanonical(resource, QuestionnaireResponse::hasQuestionnaireElement, + QuestionnaireResponse::getQuestionnaireElement, "QuestionnaireResponse.questionnaire", + Questionnaire.class); var source = getReference(resource, QuestionnaireResponse::hasSource, QuestionnaireResponse::getSource, "QuestionnaireResponse.source", Patient.class, Practitioner.class, PractitionerRole.class, RelatedPerson.class); - var subject = getReference(resource, QuestionnaireResponse::hasSubject, QuestionnaireResponse::getSubject, "QuestionnaireResponse.subject"); var extensionReferences = getExtensionReferences(resource); - return concat(author, basedOn, encounter, partOf, source, subject, extensionReferences); + return concat(author, basedOn, encounter, partOf, questionnaire, source, subject, extensionReferences); } @Override @@ -876,9 +940,13 @@ public Stream getReferences(StructureDefinition resource) if (resource == null) return Stream.empty(); + var baseDefinition = getCanonical(resource, StructureDefinition::hasBaseDefinitionElement, + StructureDefinition::getBaseDefinitionElement, "StructureDefinition.baseDefinition", + StructureDefinition.class); + var extensionReferences = getExtensionReferences(resource); - return extensionReferences; + return concat(baseDefinition, extensionReferences); } @Override @@ -899,23 +967,25 @@ public Stream getReferences(Task resource) return Stream.empty(); var basedOns = getReferences(resource, Task::hasBasedOn, Task::getBasedOn, "Task.basedOn"); - var partOfs = getReferences(resource, Task::hasPartOf, Task::getPartOf, "Task.partOf", Task.class); - var focus = getReference(resource, Task::hasFocus, Task::getFocus, "Task.focus"); - var forRef = getReference(resource, Task::hasFor, Task::getFor, "Task.for"); var encounter = getReference(resource, Task::hasEncounter, Task::getEncounter, "Task.encounter", Encounter.class); - var requester = getReference(resource, Task::hasRequester, Task::getRequester, "Task.requester", Device.class, - Organization.class, Patient.class, Practitioner.class, PractitionerRole.class, RelatedPerson.class); + var focus = getReference(resource, Task::hasFocus, Task::getFocus, "Task.focus"); + var forRef = getReference(resource, Task::hasFor, Task::getFor, "Task.for"); + var instantiatesCanonical = getCanonical(resource, Task::hasInstantiatesCanonicalElement, + Task::getInstantiatesCanonicalElement, "Task.instantiatesCanonical", ActivityDefinition.class); + var insurance = getReferences(resource, Task::hasInsurance, Task::getInsurance, "Task.insurance", + Coverage.class, ClaimResponse.class); + var location = getReference(resource, Task::hasLocation, Task::getLocation, "Task.location", Location.class); var owner = getReference(resource, Task::hasOwner, Task::getOwner, "Task.owner", Practitioner.class, PractitionerRole.class, Organization.class, CareTeam.class, HealthcareService.class, Patient.class, Device.class, RelatedPerson.class); - var location = getReference(resource, Task::hasLocation, Task::getLocation, "Task.location", Location.class); + var partOfs = getReferences(resource, Task::hasPartOf, Task::getPartOf, "Task.partOf", Task.class); var reasonReference = getReference(resource, Task::hasReasonReference, Task::getReasonReference, "Task.reasonReference"); - var insurance = getReferences(resource, Task::hasInsurance, Task::getInsurance, "Task.insurance", - Coverage.class, ClaimResponse.class); var relevanteHistories = getReferences(resource, Task::hasRelevantHistory, Task::getRelevantHistory, "Task.relevantHistory", Provenance.class); + var requester = getReference(resource, Task::hasRequester, Task::getRequester, "Task.requester", Device.class, + Organization.class, Patient.class, Practitioner.class, PractitionerRole.class, RelatedPerson.class); var restrictionRecipiets = getBackboneElementReferences(resource, Task::hasRestriction, Task::getRestriction, Task.TaskRestrictionComponent::hasRecipient, Task.TaskRestrictionComponent::getRecipient, "Task.restriction.recipient", Patient.class, Practitioner.class, PractitionerRole.class, @@ -925,8 +995,8 @@ public Stream getReferences(Task resource) var outputReferences = getOutputReferences(resource); var extensionReferences = getExtensionReferences(resource); - return concat(basedOns, partOfs, focus, forRef, encounter, requester, owner, location, reasonReference, - insurance, relevanteHistories, restrictionRecipiets, inputReferences, outputReferences, + return concat(basedOns, encounter, focus, forRef, instantiatesCanonical, insurance, location, owner, partOfs, + reasonReference, relevanteHistories, requester, restrictionRecipiets, inputReferences, outputReferences, extensionReferences); } diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/dev/dsf/fhir/service/ResourceReference.java b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/dev/dsf/fhir/service/ResourceReference.java index 7dccd6930..d4015defd 100644 --- a/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/dev/dsf/fhir/service/ResourceReference.java +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/main/java/dev/dsf/fhir/service/ResourceReference.java @@ -1,7 +1,6 @@ package dev.dsf.fhir.service; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.EnumSet; @@ -11,6 +10,7 @@ import java.util.regex.Pattern; import org.hl7.fhir.r4.model.Attachment; +import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.RelatedArtifact; @@ -143,42 +143,54 @@ public enum ReferenceType /** * unknown url in Attachment */ - ATTACHMENT_UNKNOWN_URL + ATTACHMENT_UNKNOWN_URL, + /** + * canoncial reference + */ + CANONICAL } private final String location; private final Reference reference; private final RelatedArtifact relatedArtifact; private final Attachment attachment; + private final CanonicalType canonical; private final List> referenceTypes = new ArrayList<>(); @SafeVarargs public ResourceReference(String location, Reference reference, Class... referenceTypes) { - this(location, reference, null, null, Arrays.asList(referenceTypes)); + this(location, reference, null, null, null, List.of(referenceTypes)); } public ResourceReference(String location, RelatedArtifact relatedArtifact) { - this(location, null, relatedArtifact, null, Collections.emptyList()); + this(location, null, relatedArtifact, null, null, Collections.emptyList()); } public ResourceReference(String location, Attachment attachment) { - this(location, null, null, attachment, Collections.emptyList()); + this(location, null, null, attachment, null, Collections.emptyList()); + } + + @SafeVarargs + public ResourceReference(String location, CanonicalType canonical, Class... referenceTypes) + { + this(location, null, null, null, canonical, List.of(referenceTypes)); } private ResourceReference(String location, Reference reference, RelatedArtifact relatedArtifact, - Attachment attachment, Collection> referenceTypes) + Attachment attachment, CanonicalType canonical, Collection> referenceTypes) { this.location = location; - if (reference == null && relatedArtifact == null && attachment == null) - throw new IllegalArgumentException("Either reference, relatedArtifact or attachment expected"); + if (reference == null && relatedArtifact == null && attachment == null && canonical == null) + throw new IllegalArgumentException("Either reference, relatedArtifact, attachment or canonical expected"); this.reference = reference; this.relatedArtifact = relatedArtifact; this.attachment = attachment; + this.canonical = canonical; if (referenceTypes != null) this.referenceTypes.addAll(referenceTypes); @@ -214,6 +226,16 @@ public Attachment getAttachment() return attachment; } + public boolean hasCanonical() + { + return canonical != null; + } + + public CanonicalType getCanonical() + { + return canonical; + } + public String getValue() { if (hasReference()) @@ -222,8 +244,10 @@ else if (hasRelatedArtifact()) return relatedArtifact.getUrl(); else if (hasAttachment()) return attachment.getUrl(); + else if (hasCanonical()) + return canonical.getValue(); else - throw new IllegalArgumentException("reference, related artefact or attachment not set"); + throw new IllegalArgumentException("reference, related artefact, attachment or canonical not set"); } public List> getReferenceTypes() @@ -336,8 +360,15 @@ else if (reference.hasType() && reference.hasIdentifier() && reference.getIdenti return ReferenceType.UNKNOWN; } + else if (canonical != null) + { + if (canonical.hasValue()) + return ReferenceType.CANONICAL; + else + return ReferenceType.UNKNOWN; + } else - throw new IllegalStateException("Either reference or relatedArtifact expected"); + throw new IllegalStateException("Either reference, related artefact, attachment or canonical expected"); } public String getLocation() diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractAuthorizationRule.java index b2343cc27..4e978a6e3 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/AbstractAuthorizationRule.java @@ -335,12 +335,6 @@ protected final Optional createIfLiteralInternalOrLogicalRefe return Optional.empty(); } - protected final Optional resolveReference(Connection connection, Identity identity, - Optional reference) - { - return reference.flatMap(ref -> referenceResolver.resolveReference(identity, ref, connection)); - } - @Override public Optional reasonPermanentDeleteAllowed(Identity identity, R oldResource) { diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java index dd3b3273f..ef86fe655 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java @@ -1,7 +1,6 @@ package dev.dsf.fhir.authorization; import java.sql.Connection; -import java.sql.SQLException; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; @@ -9,7 +8,6 @@ import java.util.Optional; import java.util.stream.Collectors; -import org.hl7.fhir.r4.model.Questionnaire; import org.hl7.fhir.r4.model.QuestionnaireResponse; import org.hl7.fhir.r4.model.QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent; import org.hl7.fhir.r4.model.QuestionnaireResponse.QuestionnaireResponseItemComponent; @@ -90,12 +88,8 @@ private Optional newResourceOk(Connection connection, QuestionnaireRespo getItemAndValidate(newResource, CODESYSTEM_DSF_BPMN_USER_TASK_VALUE_USER_TASK_ID, errors); - String questionnaireUrlAndVersion = newResource.getQuestionnaire(); - if (!questionnaireExists(connection, questionnaireUrlAndVersion)) - { - errors.add( - "Questionnaire ressource referenced via canonical QuestionnaireResponse.questionnaire does not exist"); - } + if (!newResource.hasQuestionnaire()) + errors.add("QuestionnaireResponse.questionnaire missing"); if (errors.isEmpty()) return Optional.empty(); @@ -150,23 +144,6 @@ private Optional getItemAndValidate(QuestionnaireResponse newResource, S return Optional.of(value.getValue()); } - private boolean questionnaireExists(Connection connection, String questionnaireUrlAndVersion) - { - try - { - Optional questionnaire = daoProvider.getQuestionnaireDao() - .readByUrlAndVersionWithTransaction(connection, questionnaireUrlAndVersion); - - return questionnaire.isPresent(); - } - catch (SQLException e) - { - logger.warn("Could not check questionnaire with url|version '{}' for questionnaire-response - {}", - questionnaireUrlAndVersion, e.getMessage()); - throw new RuntimeException(e); - } - } - @Override public Optional reasonReadAllowed(Connection connection, Identity identity, QuestionnaireResponse existingResource) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/ReferencesHelperImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/ReferencesHelperImpl.java index 21fea87ae..1890fafb4 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/ReferencesHelperImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/dao/command/ReferencesHelperImpl.java @@ -200,7 +200,7 @@ public void checkReferences(Map idTranslationTable, Connection c Predicate checkReference) throws WebApplicationException { referenceExtractor.getReferences(resource).filter(checkReference) - .filter(ref -> referenceResolver.referenceCanBeChecked(ref, connection)).forEach(ref -> + .filter(ref -> referenceResolver.referenceCanBeResolved(ref, connection)).forEach(ref -> { Optional outcome = checkReference(ref, connection); if (outcome.isPresent()) @@ -224,6 +224,9 @@ private Optional checkReference(ResourceReference reference, C case LOGICAL -> referenceResolver.checkLogicalReference(identity, resource, reference, connection, index); + case CANONICAL -> + referenceResolver.checkCanonicalReference(identity, resource, reference, connection, index); + // unknown URLs to non FHIR servers in related artifacts must not be checked case RELATED_ARTEFACT_UNKNOWN_URL, ATTACHMENT_UNKNOWN_URL -> Optional.empty(); diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolver.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolver.java index d601c234f..048d9e8ca 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolver.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolver.java @@ -35,15 +35,6 @@ public interface ReferenceResolver */ Optional resolveReference(Identity identity, ResourceReference reference, Connection connection); - /** - * @param reference - * not null - * @param connection - * not null - * @return true if the {@link ResourceReference} can be checked - */ - boolean referenceCanBeChecked(ResourceReference reference, Connection connection); - /** * @param resource * not null @@ -160,4 +151,40 @@ Optional checkLogicalReference(Identity identity, Resource res Optional checkLogicalReference(Identity identity, Resource resource, ResourceReference resourceReference, Connection connection, Integer bundleIndex) throws IllegalArgumentException; + + /** + * @param identity + * not null + * @param resource + * not null + * @param reference + * not null + * @param connection + * not null + * @return {@link Optional#empty()} if the reference check was successful + * @throws IllegalArgumentException + * if the reference is not of type {@link ResourceReference.ReferenceType#CANONICAL} + * @see ResourceReference#getType(String) + */ + Optional checkCanonicalReference(Identity identity, Resource resource, + ResourceReference reference, Connection connection) throws IllegalArgumentException; + + /** + * @param identity + * not null + * @param resource + * not null + * @param reference + * not null + * @param connection + * not null + * @param bundleIndex + * may be null + * @return {@link Optional#empty()} if the reference check was successful + * @throws IllegalArgumentException + * if the reference is not of type {@link ResourceReference.ReferenceType#CANONICAL} + * @see ResourceReference#getType(String) + */ + Optional checkCanonicalReference(Identity identity, Resource resource, + ResourceReference reference, Connection connection, Integer bundleIndex) throws IllegalArgumentException; } diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolverImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolverImpl.java index b8f59320c..3e5a64795 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolverImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/service/ReferenceResolverImpl.java @@ -2,7 +2,6 @@ import java.sql.Connection; import java.util.Arrays; -import java.util.Collections; import java.util.EnumSet; import java.util.List; import java.util.Map; @@ -41,6 +40,9 @@ public class ReferenceResolverImpl implements ReferenceResolver, InitializingBea { private static final Logger logger = LoggerFactory.getLogger(ReferenceResolverImpl.class); + private static final String QUESTIONNAIRE_RESPONSE_QUESTIONNAIRE = "QuestionnaireResponse.questionnaire"; + private static final String TASK_INSTANTIATES_CANONICAL = "Task.instantiatesCanonical"; + private final String serverBase; private final DaoProvider daoProvider; private final ResponseGenerator responseGenerator; @@ -72,12 +74,6 @@ public void afterPropertiesSet() throws Exception @Override public boolean referenceCanBeResolved(ResourceReference reference, Connection connection) - { - return referenceCanBeChecked(reference, connection); - } - - @Override - public boolean referenceCanBeChecked(ResourceReference reference, Connection connection) { Objects.requireNonNull(reference, "reference"); Objects.requireNonNull(connection, "connection"); @@ -85,36 +81,19 @@ public boolean referenceCanBeChecked(ResourceReference reference, Connection con return switch (reference.getType(serverBase)) { case LITERAL_EXTERNAL, RELATED_ARTEFACT_LITERAL_EXTERNAL_URL, ATTACHMENT_LITERAL_EXTERNAL_URL -> - literalExternalReferenceCanBeCheckedAndResolved(reference); + clientProvider.endpointExists(reference.getServerBase(serverBase)); - case LOGICAL -> logicalReferenceCanBeCheckedAndResolved(reference, connection); + case LOGICAL -> exceptionHandler.handleSqlException( + () -> daoProvider.getNamingSystemDao().existsWithUniqueIdUriEntryResolvable(connection, + reference.getReference().getIdentifier().getSystem())); + + case CANONICAL -> QUESTIONNAIRE_RESPONSE_QUESTIONNAIRE.equals(reference.getLocation()) + || TASK_INSTANTIATES_CANONICAL.equals(reference.getLocation()); default -> true; }; } - private boolean logicalReferenceCanBeCheckedAndResolved(ResourceReference reference, Connection connection) - { - if (!ReferenceType.LOGICAL.equals(reference.getType(serverBase))) - throw new IllegalArgumentException("Not a logical reference"); - - return exceptionHandler.handleSqlException( - () -> daoProvider.getNamingSystemDao().existsWithUniqueIdUriEntryResolvable(connection, - reference.getReference().getIdentifier().getSystem())); - } - - private boolean literalExternalReferenceCanBeCheckedAndResolved(ResourceReference reference) - { - if (!EnumSet.of(ReferenceType.LITERAL_EXTERNAL, ReferenceType.RELATED_ARTEFACT_LITERAL_EXTERNAL_URL, - ReferenceType.ATTACHMENT_LITERAL_EXTERNAL_URL).contains(reference.getType(serverBase))) - { - throw new IllegalArgumentException( - "Not a literal external reference, related artifact literal external url or attachment literal external url"); - } - - return clientProvider.endpointExists(reference.getServerBase(serverBase)); - } - @Override public Optional resolveReference(Identity identity, ResourceReference reference, Connection connection) { @@ -131,6 +110,7 @@ public Optional resolveReference(Identity identity, ResourceReference case CONDITIONAL, RELATED_ARTEFACT_CONDITIONAL_URL, ATTACHMENT_CONDITIONAL_URL -> resolveConditionalReference(identity, reference, connection); case LOGICAL -> resolveLogicalReference(identity, reference, connection); + default -> throw new IllegalArgumentException("Reference of type " + type + " not supported"); }; } @@ -240,7 +220,9 @@ private Optional resolveConditionalReference(Identity identity, Resour Connection connection) { Objects.requireNonNull(reference, "reference"); - throwIfReferenceTypeUnexpected(reference.getType(serverBase), ReferenceType.CONDITIONAL, + + ReferenceType referenceType = reference.getType(serverBase); + throwIfReferenceTypeUnexpected(referenceType, ReferenceType.CONDITIONAL, ReferenceType.RELATED_ARTEFACT_CONDITIONAL_URL, ReferenceType.ATTACHMENT_CONDITIONAL_URL); String referenceValue = reference.getValue(); @@ -271,7 +253,7 @@ private Optional resolveConditionalReference(Identity identity, Resour return Optional.empty(); } - return search(identity, connection, d, reference, condition.getQueryParams(), true); + return search(identity, connection, d, reference, condition.getQueryParams(), referenceType); } } @@ -302,14 +284,14 @@ private Optional resolveLogicalReference(Identity identity, ResourceRe } Identifier targetIdentifier = reference.getReference().getIdentifier(); - return search(identity, connection, d, reference, Map.of("identifier", - Collections.singletonList(targetIdentifier.getSystem() + "|" + targetIdentifier.getValue())), true); + return search(identity, connection, d, reference, + Map.of("identifier", List.of(targetIdentifier.getSystem() + "|" + targetIdentifier.getValue())), + ReferenceType.LOGICAL); } } private Optional search(Identity identity, Connection connection, ResourceDao referenceTargetDao, - ResourceReference resourceReference, Map> queryParameters, - boolean logicalNotConditional) + ResourceReference resourceReference, Map> queryParameters, ReferenceType referenceType) { if (Arrays.stream(SearchQuery.STANDARD_PARAMETERS).anyMatch(queryParameters::containsKey)) { @@ -333,11 +315,17 @@ private Optional search(Identity identity, Connection connection, Reso String unsupportedQueryParametersString = unsupportedQueryParameters.stream() .map(SearchQueryParameterError::toString).collect(Collectors.joining("; ")); - logger.warn("{} reference {} at {} in resource contains unsupported queryparameter{} {}", - logicalNotConditional ? "Logical" : "Conditional", queryParameters, resourceReference.getLocation(), - unsupportedQueryParameters.size() != 1 ? "s" : "", unsupportedQueryParametersString); - - return Optional.empty(); + if (EnumSet.of(ReferenceType.CONDITIONAL, ReferenceType.RELATED_ARTEFACT_CONDITIONAL_URL, + ReferenceType.ATTACHMENT_CONDITIONAL_URL).contains(referenceType)) + { + logger.warn("Conditional reference {} at {} in resource contains unsupported queryparameter{} {}", + queryParameters, resourceReference.getLocation(), + unsupportedQueryParameters.size() != 1 ? "s" : "", unsupportedQueryParametersString); + return Optional.empty(); + } + else + throw new IllegalStateException("Unable to search for " + referenceTargetDao.getResourceTypeName() + + ": Unsupported query parameters"); } PartialResult result = exceptionHandler.handleSqlException(() -> @@ -348,39 +336,26 @@ private Optional search(Identity identity, Connection connection, Reso return referenceTargetDao.searchWithTransaction(connection, query); }); - if (result.getTotal() <= 0) - { - if (logicalNotConditional) - logger.warn("Reference target by identifier '{}|{}' of reference at {} in resource", - resourceReference.getReference().getIdentifier().getSystem(), - resourceReference.getReference().getIdentifier().getValue(), resourceReference.getLocation()); - else - logger.warn("Reference target by condition '{}' of reference at {} in resource", - UriComponentsBuilder.newInstance().path(referenceTargetDao.getResourceTypeName()) - .replaceQueryParams(CollectionUtils.toMultiValueMap(queryParameters)).toUriString(), - resourceReference.getLocation()); - - return Optional.empty(); - } - else if (result.getTotal() == 1) - { + if (result.getTotal() == 1) return Optional.of(result.getPartialResult().get(0)); - } - else // if (result.getOverallCount() > 1) + + else { int overallCount = result.getTotal(); - if (logicalNotConditional) - logger.warn( - "Found {} matches for reference target by identifier '{}|{}' of reference at {} in resource", - overallCount, resourceReference.getReference().getIdentifier().getSystem(), - resourceReference.getReference().getIdentifier().getValue(), resourceReference.getLocation()); - else - logger.warn("Found {} matches for reference target by condition '{}' of reference at {} in resource", - overallCount, + if (ReferenceType.LOGICAL.equals(referenceType)) + logger.warn("Found {} matches for reference at {} with identifier '{}|{}'", overallCount, + resourceReference.getLocation(), resourceReference.getReference().getIdentifier().getSystem(), + resourceReference.getReference().getIdentifier().getValue()); + else if (EnumSet.of(ReferenceType.CONDITIONAL, ReferenceType.RELATED_ARTEFACT_CONDITIONAL_URL, + ReferenceType.ATTACHMENT_CONDITIONAL_URL).contains(referenceType)) + logger.warn("Found {} matches for reference at {} with condition '{}'", overallCount, + resourceReference.getLocation(), UriComponentsBuilder.newInstance().path(referenceTargetDao.getResourceTypeName()) - .replaceQueryParams(CollectionUtils.toMultiValueMap(queryParameters)).toUriString(), - resourceReference.getLocation()); + .replaceQueryParams(CollectionUtils.toMultiValueMap(queryParameters)).toUriString()); + else if (ReferenceType.CANONICAL.equals(referenceType)) + logger.warn("Found {} matches for reference at {} with url '{}'", overallCount, + resourceReference.getLocation(), resourceReference.getCanonical().getValue()); return Optional.empty(); } @@ -558,8 +533,9 @@ public Optional checkLogicalReference(Identity identity, Resou Identifier targetIdentifier = reference.getReference().getIdentifier(); // Resource target = - return search(identity, resource, bundleIndex, connection, d, reference, Map.of("identifier", - Collections.singletonList(targetIdentifier.getSystem() + "|" + targetIdentifier.getValue())), true); + return search(identity, resource, bundleIndex, connection, d, reference, + Map.of("identifier", List.of(targetIdentifier.getSystem() + "|" + targetIdentifier.getValue())), + true); // resourceReference.getReference().setIdentifier(null).setReferenceElement( // new IdType(target.getResourceType().name(), target.getIdElement().getIdPart())); @@ -627,4 +603,46 @@ else if (result.getTotal() == 1) resource, resourceReference, result.getTotal())); } } + + @Override + public Optional checkCanonicalReference(Identity identity, Resource resource, + ResourceReference reference, Connection connection) throws IllegalArgumentException + { + return checkCanonicalReference(identity, resource, reference, connection, null); + } + + @Override + public Optional checkCanonicalReference(Identity identity, Resource resource, + ResourceReference reference, Connection connection, Integer bundleIndex) throws IllegalArgumentException + { + Objects.requireNonNull(identity, "identity"); + Objects.requireNonNull(resource, "resource"); + Objects.requireNonNull(reference, "reference"); + Objects.requireNonNull(connection, "connection"); + throwIfReferenceTypeUnexpected(reference.getType(serverBase), ReferenceType.CANONICAL); + + Optional> referenceDao = switch (reference.getLocation()) + { + case QUESTIONNAIRE_RESPONSE_QUESTIONNAIRE -> Optional.of(daoProvider.getQuestionnaireDao()); + case TASK_INSTANTIATES_CANONICAL -> Optional.of(daoProvider.getActivityDefinitionDao()); + + default -> Optional.empty(); + }; + + if (referenceDao.isEmpty()) + { + logger.debug( + "Canonical reference check only implemented for QuestionnaireResponse.questionnaire and Task.instantiatesCanonical, not checking {}", + reference.getLocation()); + return Optional.empty(); + } + + Optional referencedResource = referenceDao.flatMap(dao -> search(identity, connection, dao, reference, + Map.of("url", List.of(reference.getCanonical().getValue())), ReferenceType.CANONICAL)); + + if (referencedResource.isPresent()) + return Optional.empty(); + else + return Optional.of(responseGenerator.referenceTargetNotFoundLocally(bundleIndex, resource, reference)); + } } \ No newline at end of file diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java index 1778674d7..a97e8c735 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/webservice/impl/AbstractResourceServiceImpl.java @@ -243,7 +243,7 @@ private void checkReferences(Resource resource, Connection connection, Predicate throws WebApplicationException { referenceExtractor.getReferences(resource).filter(checkReference) - .filter(ref -> referenceResolver.referenceCanBeChecked(ref, connection)).forEach(ref -> + .filter(ref -> referenceResolver.referenceCanBeResolved(ref, connection)).forEach(ref -> { Optional outcome = checkReference(resource, connection, ref); if (outcome.isPresent()) @@ -268,6 +268,9 @@ private Optional checkReference(Resource resource, Connection case LOGICAL -> referenceResolver.checkLogicalReference(getCurrentIdentity(), resource, reference, connection); + case CANONICAL -> + referenceResolver.checkCanonicalReference(getCurrentIdentity(), resource, reference, connection); + // unknown URLs to non FHIR servers in related artifacts must not be checked case RELATED_ARTEFACT_UNKNOWN_URL, ATTACHMENT_UNKNOWN_URL -> Optional.empty(); diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireResponseIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireResponseIntegrationTest.java index 84966dddd..d93a490ed 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireResponseIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireResponseIntegrationTest.java @@ -41,7 +41,7 @@ public void testCreateValidByLocalUser() throws Exception } @Test - public void testCreateNotAllowedByLocalUser() throws Exception + public void testCreateNotAllowedByLocalUserStatusCompleted() throws Exception { QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse(); questionnaireResponse.setStatus(QuestionnaireResponseStatus.COMPLETED); @@ -49,6 +49,14 @@ public void testCreateNotAllowedByLocalUser() throws Exception expectForbidden(() -> getWebserviceClient().create(questionnaireResponse)); } + @Test + public void testCreateNotAllowedByLocalUserQuestionnaireDoesNotExists() throws Exception + { + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse(); + + expectForbidden(() -> getWebserviceClient().create(questionnaireResponse)); + } + @Test public void testCreateNotAllowedByRemoteUser() throws Exception { diff --git a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java index 38c010c1f..b1dc6d7bb 100644 --- a/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java +++ b/dsf-fhir/dsf-fhir-server/src/test/java/dev/dsf/fhir/integration/QuestionnaireVsQuestionnaireResponseIntegrationTest.java @@ -186,4 +186,17 @@ public void testPostQuestionnaireAndCorrespondingQuestionnaireResponseInTransact assertTrue(getWebserviceClient().postBundle(bundle).getEntry().stream() .allMatch(entry -> entry.getResponse().getStatus().equals("201 Created"))); } + + @Test + public void testPostQuestionnaireResponseInTransactionBundleQuestionnaireDoesNotExistForbidden() throws Exception + { + QuestionnaireResponse questionnaireResponse = createQuestionnaireResponse("1.5.3"); + + Bundle bundle = new Bundle(); + bundle.setType(Bundle.BundleType.TRANSACTION); + bundle.addEntry().setResource(questionnaireResponse).setFullUrl("urn:uuid:" + UUID.randomUUID().toString()) + .getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl(ResourceType.QuestionnaireResponse.name()); + + expectForbidden(() -> getWebserviceClient().postBundle(bundle)); + } } \ No newline at end of file From 26fb156318ef00253388fb0c97c236279d7ca727 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Wed, 2 Oct 2024 20:56:09 +0200 Subject: [PATCH 21/26] remove not needed parameter from private method --- .../QuestionnaireResponseAuthorizationRule.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java index ef86fe655..a47fb36c4 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/authorization/QuestionnaireResponseAuthorizationRule.java @@ -48,8 +48,7 @@ public Optional reasonCreateAllowed(Connection connection, Identity iden { if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.CREATE)) { - Optional errors = newResourceOk(connection, newResource, - EnumSet.of(QuestionnaireResponseStatus.INPROGRESS)); + Optional errors = newResourceOk(newResource, EnumSet.of(QuestionnaireResponseStatus.INPROGRESS)); if (errors.isEmpty()) { // TODO implement unique criteria based on UserTask.id when implemented as identifier @@ -69,7 +68,7 @@ public Optional reasonCreateAllowed(Connection connection, Identity iden } } - private Optional newResourceOk(Connection connection, QuestionnaireResponse newResource, + private Optional newResourceOk(QuestionnaireResponse newResource, EnumSet allowedStatus) { List errors = new ArrayList<>(); @@ -166,7 +165,7 @@ public Optional reasonUpdateAllowed(Connection connection, Identity iden { if (identity.isLocalIdentity() && identity.hasDsfRole(FhirServerRole.UPDATE)) { - Optional errors = newResourceOk(connection, newResource, + Optional errors = newResourceOk(newResource, EnumSet.of(QuestionnaireResponseStatus.COMPLETED, QuestionnaireResponseStatus.STOPPED)); if (errors.isEmpty()) { From 990f94d851a1a6d7b961bc15cb4b9e2bb0b62144 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Tue, 8 Oct 2024 19:13:22 +0200 Subject: [PATCH 22/26] dependency and maven plugin version upgrades Code changes to reflect camunda 7.21 -> 7.22. upgrade. Reconfigured log4j to suppress config messages on startup to system out. --- dsf-bpe/dsf-bpe-server-jetty/conf/log4j2.xml | 2 +- .../docker/conf/log4j2.xml | 2 +- ...rsionSpringProcessEngineConfiguration.java | 13 +--- .../dsf/bpe/spring/config/CamundaConfig.java | 4 -- .../camunda/postgres_engine_7.21_to_7.22.sql | 29 +++++++++ .../db/db.camunda_engine.changelog-1.6.0.xml | 12 ++++ .../src/main/resources/db/db.changelog.xml | 2 + .../src/test/resources/log4j2.xml | 2 +- .../src/test/resources/log4j2.xml | 2 +- .../src/test/resources/log4j2.xml | 2 +- .../src/test/resources/log4j2.xml | 2 +- .../src/test/resources/log4j2.xml | 2 +- .../src/test/resources/log4j2.xml | 2 +- .../dsf-fhir-server-jetty/conf/log4j2.xml | 2 +- .../docker/conf/log4j2.xml | 2 +- .../log4j2-maven-surefire-config.xml | 2 +- .../src/test/resources/log4j2.xml | 2 +- .../src/test/resources/log4j2.xml | 2 +- .../src/main/resources/log4j2.xml | 2 +- .../src/main/resources/log4j2.xml | 2 +- .../src/main/resources/log4j2.xml | 2 +- .../src/main/resources/log4j2.xml | 2 +- pom.xml | 60 +++++++++---------- 23 files changed, 93 insertions(+), 61 deletions(-) create mode 100644 dsf-bpe/dsf-bpe-server/src/main/resources/db/camunda/postgres_engine_7.21_to_7.22.sql create mode 100644 dsf-bpe/dsf-bpe-server/src/main/resources/db/db.camunda_engine.changelog-1.6.0.xml diff --git a/dsf-bpe/dsf-bpe-server-jetty/conf/log4j2.xml b/dsf-bpe/dsf-bpe-server-jetty/conf/log4j2.xml index 0c1747aa9..812d34c8f 100755 --- a/dsf-bpe/dsf-bpe-server-jetty/conf/log4j2.xml +++ b/dsf-bpe/dsf-bpe-server-jetty/conf/log4j2.xml @@ -1,4 +1,4 @@ - diff --git a/dsf-bpe/dsf-bpe-server-jetty/docker/conf/log4j2.xml b/dsf-bpe/dsf-bpe-server-jetty/docker/conf/log4j2.xml index bc09f21e4..57699e922 100644 --- a/dsf-bpe/dsf-bpe-server-jetty/docker/conf/log4j2.xml +++ b/dsf-bpe/dsf-bpe-server-jetty/docker/conf/log4j2.xml @@ -1,4 +1,4 @@ - + diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/camunda/MultiVersionSpringProcessEngineConfiguration.java b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/camunda/MultiVersionSpringProcessEngineConfiguration.java index e6369efc7..7ef3eab84 100644 --- a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/camunda/MultiVersionSpringProcessEngineConfiguration.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/camunda/MultiVersionSpringProcessEngineConfiguration.java @@ -11,17 +11,10 @@ public MultiVersionSpringProcessEngineConfiguration(DelegateProvider delegatePro } @Override - protected void initTelemetry() + protected void initDiagnostics() { // override to turn telemetry collection of - // see also CamundaConfig - } - @Override - public TelemetryDataImpl getTelemetryData() - { - // NPE fix after turning off telemetry collection - // see also CamundaConfig - return new TelemetryDataImpl(null, null); + setTelemetryData(new TelemetryDataImpl(null, null)); } -} +} \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/spring/config/CamundaConfig.java b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/spring/config/CamundaConfig.java index e2c95a525..5d73a60fb 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/spring/config/CamundaConfig.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/spring/config/CamundaConfig.java @@ -124,10 +124,6 @@ public SpringProcessEngineConfiguration processEngineConfiguration() serializerConfig.fhirResourceSerializer(), serializerConfig.fhirResourcesListSerializer())); c.setFallbackSerializerFactory(fallbackSerializerFactory()); - // see also MultiVersionSpringProcessEngineConfiguration - c.setInitializeTelemetry(false); - c.setTelemetryReporterActivate(false); - DefaultJobExecutor jobExecutor = new DefaultJobExecutor(); jobExecutor.setCorePoolSize(propertiesConfig.getProcessEngineJobExecutorCorePoolSize()); jobExecutor.setQueueSize(propertiesConfig.getProcessEngineJobExecutorQueueSize()); diff --git a/dsf-bpe/dsf-bpe-server/src/main/resources/db/camunda/postgres_engine_7.21_to_7.22.sql b/dsf-bpe/dsf-bpe-server/src/main/resources/db/camunda/postgres_engine_7.21_to_7.22.sql new file mode 100644 index 000000000..55583c6f4 --- /dev/null +++ b/dsf-bpe/dsf-bpe-server/src/main/resources/db/camunda/postgres_engine_7.21_to_7.22.sql @@ -0,0 +1,29 @@ +-- +-- Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH +-- under one or more contributor license agreements. See the NOTICE file +-- distributed with this work for additional information regarding copyright +-- ownership. Camunda licenses this file to you under the Apache License, +-- Version 2.0; you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +insert into ACT_GE_SCHEMA_LOG +values ('1100', CURRENT_TIMESTAMP, '7.22.0'); + +alter table ACT_RU_TASK add column TASK_STATE_ varchar(64); + +alter table ACT_HI_TASKINST add column TASK_STATE_ varchar(64); + +alter table ACT_RU_JOB add column BATCH_ID_ varchar(64); +alter table ACT_HI_JOB_LOG add column BATCH_ID_ varchar(64); + +alter table ACT_HI_PROCINST add RESTARTED_PROC_INST_ID_ varchar(64); +create index ACT_IDX_HI_PRO_RST_PRO_INST_ID on ACT_HI_PROCINST(RESTARTED_PROC_INST_ID_); diff --git a/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.camunda_engine.changelog-1.6.0.xml b/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.camunda_engine.changelog-1.6.0.xml new file mode 100644 index 000000000..c6967db93 --- /dev/null +++ b/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.camunda_engine.changelog-1.6.0.xml @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.changelog.xml b/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.changelog.xml index 7dff2d181..865d2bd97 100644 --- a/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.changelog.xml +++ b/dsf-bpe/dsf-bpe-server/src/main/resources/db/db.changelog.xml @@ -17,4 +17,6 @@ + + \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-server/src/test/resources/log4j2.xml b/dsf-bpe/dsf-bpe-server/src/test/resources/log4j2.xml index 4095d8e49..42507e66a 100755 --- a/dsf-bpe/dsf-bpe-server/src/test/resources/log4j2.xml +++ b/dsf-bpe/dsf-bpe-server/src/test/resources/log4j2.xml @@ -1,4 +1,4 @@ - diff --git a/dsf-common/dsf-common-auth/src/test/resources/log4j2.xml b/dsf-common/dsf-common-auth/src/test/resources/log4j2.xml index 96df92ff8..ea8c9d0c4 100644 --- a/dsf-common/dsf-common-auth/src/test/resources/log4j2.xml +++ b/dsf-common/dsf-common-auth/src/test/resources/log4j2.xml @@ -1,4 +1,4 @@ - + diff --git a/dsf-common/dsf-common-config/src/test/resources/log4j2.xml b/dsf-common/dsf-common-config/src/test/resources/log4j2.xml index aa5ddf5a5..ec2b86c10 100644 --- a/dsf-common/dsf-common-config/src/test/resources/log4j2.xml +++ b/dsf-common/dsf-common-config/src/test/resources/log4j2.xml @@ -1,4 +1,4 @@ - + diff --git a/dsf-common/dsf-common-jetty/src/test/resources/log4j2.xml b/dsf-common/dsf-common-jetty/src/test/resources/log4j2.xml index aa5ddf5a5..ec2b86c10 100644 --- a/dsf-common/dsf-common-jetty/src/test/resources/log4j2.xml +++ b/dsf-common/dsf-common-jetty/src/test/resources/log4j2.xml @@ -1,4 +1,4 @@ - + diff --git a/dsf-fhir/dsf-fhir-auth/src/test/resources/log4j2.xml b/dsf-fhir/dsf-fhir-auth/src/test/resources/log4j2.xml index 116ccf90e..7bafc4cfc 100644 --- a/dsf-fhir/dsf-fhir-auth/src/test/resources/log4j2.xml +++ b/dsf-fhir/dsf-fhir-auth/src/test/resources/log4j2.xml @@ -1,4 +1,4 @@ - + diff --git a/dsf-fhir/dsf-fhir-rest-adapter/src/test/resources/log4j2.xml b/dsf-fhir/dsf-fhir-rest-adapter/src/test/resources/log4j2.xml index d5beb117e..6d88f4a92 100644 --- a/dsf-fhir/dsf-fhir-rest-adapter/src/test/resources/log4j2.xml +++ b/dsf-fhir/dsf-fhir-rest-adapter/src/test/resources/log4j2.xml @@ -1,4 +1,4 @@ - + diff --git a/dsf-fhir/dsf-fhir-server-jetty/conf/log4j2.xml b/dsf-fhir/dsf-fhir-server-jetty/conf/log4j2.xml index 20ab24b03..22562c0d5 100755 --- a/dsf-fhir/dsf-fhir-server-jetty/conf/log4j2.xml +++ b/dsf-fhir/dsf-fhir-server-jetty/conf/log4j2.xml @@ -1,4 +1,4 @@ - diff --git a/dsf-fhir/dsf-fhir-server-jetty/docker/conf/log4j2.xml b/dsf-fhir/dsf-fhir-server-jetty/docker/conf/log4j2.xml index ddc27f007..4a47ab17b 100644 --- a/dsf-fhir/dsf-fhir-server-jetty/docker/conf/log4j2.xml +++ b/dsf-fhir/dsf-fhir-server-jetty/docker/conf/log4j2.xml @@ -1,4 +1,4 @@ - + diff --git a/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2-maven-surefire-config.xml b/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2-maven-surefire-config.xml index d72cf2a72..9c5baf9ed 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2-maven-surefire-config.xml +++ b/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2-maven-surefire-config.xml @@ -1,4 +1,4 @@ - + diff --git a/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2.xml b/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2.xml index aa5ddf5a5..ec2b86c10 100755 --- a/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2.xml +++ b/dsf-fhir/dsf-fhir-server/src/test/resources/log4j2.xml @@ -1,4 +1,4 @@ - + diff --git a/dsf-fhir/dsf-fhir-validation/src/test/resources/log4j2.xml b/dsf-fhir/dsf-fhir-validation/src/test/resources/log4j2.xml index 116ccf90e..7bafc4cfc 100644 --- a/dsf-fhir/dsf-fhir-validation/src/test/resources/log4j2.xml +++ b/dsf-fhir/dsf-fhir-validation/src/test/resources/log4j2.xml @@ -1,4 +1,4 @@ - + diff --git a/dsf-tools/dsf-tools-bundle-generator/src/main/resources/log4j2.xml b/dsf-tools/dsf-tools-bundle-generator/src/main/resources/log4j2.xml index 896f07998..e8fb24d29 100755 --- a/dsf-tools/dsf-tools-bundle-generator/src/main/resources/log4j2.xml +++ b/dsf-tools/dsf-tools-bundle-generator/src/main/resources/log4j2.xml @@ -1,4 +1,4 @@ - + diff --git a/dsf-tools/dsf-tools-documentation-generator/src/main/resources/log4j2.xml b/dsf-tools/dsf-tools-documentation-generator/src/main/resources/log4j2.xml index 896f07998..e8fb24d29 100755 --- a/dsf-tools/dsf-tools-documentation-generator/src/main/resources/log4j2.xml +++ b/dsf-tools/dsf-tools-documentation-generator/src/main/resources/log4j2.xml @@ -1,4 +1,4 @@ - + diff --git a/dsf-tools/dsf-tools-proxy-test/src/main/resources/log4j2.xml b/dsf-tools/dsf-tools-proxy-test/src/main/resources/log4j2.xml index 630850f14..bcf6fe9a0 100755 --- a/dsf-tools/dsf-tools-proxy-test/src/main/resources/log4j2.xml +++ b/dsf-tools/dsf-tools-proxy-test/src/main/resources/log4j2.xml @@ -1,4 +1,4 @@ - diff --git a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/log4j2.xml b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/log4j2.xml index 6e8a1fa98..e3832195b 100755 --- a/dsf-tools/dsf-tools-test-data-generator/src/main/resources/log4j2.xml +++ b/dsf-tools/dsf-tools-test-data-generator/src/main/resources/log4j2.xml @@ -1,4 +1,4 @@ - + diff --git a/pom.xml b/pom.xml index 1aedbe243..5590e8953 100755 --- a/pom.xml +++ b/pom.xml @@ -21,14 +21,14 @@ ${project.basedir} - 2.0.13 - 2.23.1 - 11.0.22 - 3.1.7 - 2.1.5 - 6.1.10 - 2.17.2 - 7.21.0 + 2.0.16 + 2.24.1 + 11.0.24 + 3.1.9 + 2.2.0 + 6.1.13 + 2.18.0 + 7.22.0 5.1.0 1.78.1 @@ -134,7 +134,7 @@ org.mockito mockito-core - 5.12.0 + 5.14.1 org.bouncycastle @@ -156,12 +156,12 @@ org.liquibase liquibase-core - 4.28.0 + 4.29.2 org.postgresql postgresql - 42.7.3 + 42.7.4 @@ -392,7 +392,7 @@ org.apache.commons commons-compress - 1.26.2 + 1.27.1 org.apache.commons @@ -423,12 +423,12 @@ commons-io commons-io - 2.16.1 + 2.17.0 commons-codec commons-codec - 1.17.0 + 1.17.1 @@ -450,7 +450,7 @@ org.yaml snakeyaml - 2.2 + 2.3 @@ -463,17 +463,17 @@ org.apache.maven maven-core - 3.9.8 + 3.9.9 org.apache.maven maven-plugin-api - 3.9.8 + 3.9.9 org.apache.maven.plugin-tools maven-plugin-annotations - 3.13.1 + 3.15.0 @@ -511,17 +511,17 @@ org.apache.maven.plugins maven-javadoc-plugin - 3.7.0 + 3.10.1 org.apache.maven.plugins maven-surefire-plugin - 3.3.0 + 3.5.1 org.apache.maven.plugins maven-failsafe-plugin - 3.3.0 + 3.5.1 org.apache.maven.plugins @@ -541,7 +541,7 @@ org.apache.maven.plugins maven-gpg-plugin - 3.2.4 + 3.2.7 org.codehaus.mojo @@ -562,22 +562,22 @@ net.revelc.code impsort-maven-plugin - 1.11.0 + 1.12.0 org.apache.maven.plugins maven-dependency-plugin - 3.7.1 + 3.8.0 org.codehaus.mojo buildnumber-maven-plugin - 3.2.0 + 3.2.1 org.apache.maven.plugins maven-plugin-plugin - 3.13.1 + 3.15.0 dev.dsf @@ -592,22 +592,22 @@ org.apache.maven.plugins maven-site-plugin - 3.12.1 + 3.20.0 com.github.spotbugs spotbugs-maven-plugin - 4.8.6.2 + 4.8.6.4 org.apache.maven.plugins maven-project-info-reports-plugin - 3.6.1 + 3.7.0 org.apache.maven.plugins maven-pmd-plugin - 3.23.0 + 3.25.0 From b7e74196ab05f2f65aa6a22ea287f151d2122f13 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Mon, 14 Oct 2024 20:24:37 +0200 Subject: [PATCH 23/26] set level DEBUG for 'de.dkfz.nct' in default bpe log config --- dsf-bpe/dsf-bpe-server-jetty/docker/conf/log4j2.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/dsf-bpe/dsf-bpe-server-jetty/docker/conf/log4j2.xml b/dsf-bpe/dsf-bpe-server-jetty/docker/conf/log4j2.xml index 57699e922..a1b66a89b 100644 --- a/dsf-bpe/dsf-bpe-server-jetty/docker/conf/log4j2.xml +++ b/dsf-bpe/dsf-bpe-server-jetty/docker/conf/log4j2.xml @@ -17,6 +17,7 @@ + From a462213b701e850d460cf98f392cb43b54286cb0 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Mon, 14 Oct 2024 20:26:33 +0200 Subject: [PATCH 24/26] upgraded keycloak in 3dic/ttp test setup: 21.0 -> 25.0 no upgrading to 26.0, import of realms not working --- dsf-docker-test-setup-3dic-ttp/docker-compose.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dsf-docker-test-setup-3dic-ttp/docker-compose.yml b/dsf-docker-test-setup-3dic-ttp/docker-compose.yml index 5895c6bd5..b7302d664 100644 --- a/dsf-docker-test-setup-3dic-ttp/docker-compose.yml +++ b/dsf-docker-test-setup-3dic-ttp/docker-compose.yml @@ -78,7 +78,7 @@ services: read_only: true keycloak: - image: quay.io/keycloak/keycloak:21.0 + image: quay.io/keycloak/keycloak:25.0 restart: "no" ports: - 127.0.0.1:8443:8443 @@ -104,7 +104,7 @@ services: --https-certificate-key-file=/run/secrets/keycloak_certificate_private_key.pem --spi-truststore-file-file=/run/secrets/keycloak_trust_store.jks --spi-truststore-file-password=password - --spi-truststore-file-hostname-verification-policy=STRICT + --spi-truststore-file-hostname-verification-policy=DEFAULT forward-proxy: build: ./forward-proxy From 68e6ba9d227c5c0e5dfa4a14a2d4081b82b5f887 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Tue, 15 Oct 2024 12:48:42 +0200 Subject: [PATCH 25/26] added allowlist management publication --- CITATION.cff | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CITATION.cff b/CITATION.cff index 00c124f71..11751ff56 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -241,3 +241,23 @@ references: year: 2024 pages: 28-32 doi: 10.3233/SHTI230921 + - type: proceedings + authors: + - family-names: Schweizer + given-names: Simon Tobias + - family-names: Hund + given-names: Hauke + - family-names: Kurscheidt + given-names: Maximilian + - family-names: Zilske + given-names: Christoph + - family-names: Böhringer + given-names: Jan P. + - family-names: Fegeler + given-names: Christian + title: "Handling Complexity in Decentralized Research Networks: The Data Sharing Framework Allowlist Management Application" + journal: Stud Health Technol Inform + volume: 317 + year: 2024 + pages: 85-93 + doi: 10.3233/SHTI240841 \ No newline at end of file From e3c59c546214b62efe4d89943f8889528f7a0194 Mon Sep 17 00:00:00 2001 From: Hauke Hund Date: Tue, 15 Oct 2024 12:51:12 +0200 Subject: [PATCH 26/26] 1.6.0 release --- CITATION.cff | 4 ++-- dsf-bpe/dsf-bpe-process-api-v1/pom.xml | 2 +- dsf-bpe/dsf-bpe-server-jetty/pom.xml | 2 +- dsf-bpe/dsf-bpe-server/pom.xml | 2 +- dsf-bpe/pom.xml | 2 +- dsf-common/dsf-common-auth/pom.xml | 2 +- dsf-common/dsf-common-config/pom.xml | 2 +- dsf-common/dsf-common-db/pom.xml | 2 +- dsf-common/dsf-common-documentation/pom.xml | 2 +- dsf-common/dsf-common-jetty/pom.xml | 2 +- dsf-common/dsf-common-status/pom.xml | 2 +- dsf-common/dsf-common-ui/pom.xml | 2 +- dsf-common/pom.xml | 2 +- dsf-fhir/dsf-fhir-auth/pom.xml | 2 +- dsf-fhir/dsf-fhir-rest-adapter/pom.xml | 2 +- dsf-fhir/dsf-fhir-server-jetty/pom.xml | 2 +- dsf-fhir/dsf-fhir-server/pom.xml | 2 +- dsf-fhir/dsf-fhir-validation/pom.xml | 4 ++-- dsf-fhir/dsf-fhir-webservice-client/pom.xml | 2 +- dsf-fhir/dsf-fhir-websocket-client/pom.xml | 2 +- dsf-fhir/pom.xml | 2 +- dsf-tools/dsf-tools-build-info-reader/pom.xml | 2 +- dsf-tools/dsf-tools-bundle-generator/pom.xml | 2 +- dsf-tools/dsf-tools-db-migration/pom.xml | 2 +- dsf-tools/dsf-tools-docker-secrets-reader/pom.xml | 2 +- dsf-tools/dsf-tools-documentation-generator/pom.xml | 2 +- dsf-tools/dsf-tools-proxy-test/pom.xml | 2 +- dsf-tools/dsf-tools-test-data-generator/pom.xml | 2 +- dsf-tools/pom.xml | 2 +- pom.xml | 2 +- 30 files changed, 32 insertions(+), 32 deletions(-) diff --git a/CITATION.cff b/CITATION.cff index 11751ff56..44ba85c1a 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -24,8 +24,8 @@ preferred-citation: doi: 10.3233/SHTI210060 type: proceedings title: "Data Sharing Framework (DSF)" -version: 1.5.3 -date-released: 2024-07-15 +version: 1.6.0 +date-released: 2024-10-15 url: https://dsf.dev repository-code: https://github.com/datasharingframework/dsf repository-artifact: https://github.com/datasharingframework/dsf/releases diff --git a/dsf-bpe/dsf-bpe-process-api-v1/pom.xml b/dsf-bpe/dsf-bpe-process-api-v1/pom.xml index 590d5aea3..3c07a3a54 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1/pom.xml +++ b/dsf-bpe/dsf-bpe-process-api-v1/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-bpe-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-bpe/dsf-bpe-server-jetty/pom.xml b/dsf-bpe/dsf-bpe-server-jetty/pom.xml index 70ba7f1c9..66601906b 100755 --- a/dsf-bpe/dsf-bpe-server-jetty/pom.xml +++ b/dsf-bpe/dsf-bpe-server-jetty/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-bpe-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-bpe/dsf-bpe-server/pom.xml b/dsf-bpe/dsf-bpe-server/pom.xml index 65e045807..1f55d19ef 100755 --- a/dsf-bpe/dsf-bpe-server/pom.xml +++ b/dsf-bpe/dsf-bpe-server/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-bpe-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-bpe/pom.xml b/dsf-bpe/pom.xml index 58ee7676b..c8385bf86 100755 --- a/dsf-bpe/pom.xml +++ b/dsf-bpe/pom.xml @@ -7,7 +7,7 @@ dev.dsf dsf-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-common/dsf-common-auth/pom.xml b/dsf-common/dsf-common-auth/pom.xml index d3e5cdfbb..2a8405acd 100644 --- a/dsf-common/dsf-common-auth/pom.xml +++ b/dsf-common/dsf-common-auth/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-common-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-common/dsf-common-config/pom.xml b/dsf-common/dsf-common-config/pom.xml index 28dae4c4a..8de27364f 100644 --- a/dsf-common/dsf-common-config/pom.xml +++ b/dsf-common/dsf-common-config/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-common-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-common/dsf-common-db/pom.xml b/dsf-common/dsf-common-db/pom.xml index ab0f52280..f1ffab452 100644 --- a/dsf-common/dsf-common-db/pom.xml +++ b/dsf-common/dsf-common-db/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-common-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-common/dsf-common-documentation/pom.xml b/dsf-common/dsf-common-documentation/pom.xml index c0ee493fd..519927168 100644 --- a/dsf-common/dsf-common-documentation/pom.xml +++ b/dsf-common/dsf-common-documentation/pom.xml @@ -6,6 +6,6 @@ dev.dsf dsf-common-pom - 1.6.0-SNAPSHOT + 1.6.0 \ No newline at end of file diff --git a/dsf-common/dsf-common-jetty/pom.xml b/dsf-common/dsf-common-jetty/pom.xml index 121832aa3..344627b9b 100644 --- a/dsf-common/dsf-common-jetty/pom.xml +++ b/dsf-common/dsf-common-jetty/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-common-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-common/dsf-common-status/pom.xml b/dsf-common/dsf-common-status/pom.xml index b560bb5f0..d3cec2efa 100644 --- a/dsf-common/dsf-common-status/pom.xml +++ b/dsf-common/dsf-common-status/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-common-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-common/dsf-common-ui/pom.xml b/dsf-common/dsf-common-ui/pom.xml index cfd3015e8..92a5181e4 100644 --- a/dsf-common/dsf-common-ui/pom.xml +++ b/dsf-common/dsf-common-ui/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-common-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-common/pom.xml b/dsf-common/pom.xml index b699c5af2..1695eaa6d 100644 --- a/dsf-common/pom.xml +++ b/dsf-common/pom.xml @@ -7,7 +7,7 @@ dev.dsf dsf-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-fhir/dsf-fhir-auth/pom.xml b/dsf-fhir/dsf-fhir-auth/pom.xml index 159d12a0b..2ad162878 100644 --- a/dsf-fhir/dsf-fhir-auth/pom.xml +++ b/dsf-fhir/dsf-fhir-auth/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-fhir/dsf-fhir-rest-adapter/pom.xml b/dsf-fhir/dsf-fhir-rest-adapter/pom.xml index 9843f2377..4ab782735 100755 --- a/dsf-fhir/dsf-fhir-rest-adapter/pom.xml +++ b/dsf-fhir/dsf-fhir-rest-adapter/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-fhir/dsf-fhir-server-jetty/pom.xml b/dsf-fhir/dsf-fhir-server-jetty/pom.xml index 2f4aa481c..208bcf1c6 100755 --- a/dsf-fhir/dsf-fhir-server-jetty/pom.xml +++ b/dsf-fhir/dsf-fhir-server-jetty/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-fhir/dsf-fhir-server/pom.xml b/dsf-fhir/dsf-fhir-server/pom.xml index 3a3a95258..9141551d6 100755 --- a/dsf-fhir/dsf-fhir-server/pom.xml +++ b/dsf-fhir/dsf-fhir-server/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-fhir/dsf-fhir-validation/pom.xml b/dsf-fhir/dsf-fhir-validation/pom.xml index 74c96a2bb..aac5b274f 100644 --- a/dsf-fhir/dsf-fhir-validation/pom.xml +++ b/dsf-fhir/dsf-fhir-validation/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.6.0-SNAPSHOT + 1.6.0 @@ -104,7 +104,7 @@ - diff --git a/dsf-fhir/dsf-fhir-webservice-client/pom.xml b/dsf-fhir/dsf-fhir-webservice-client/pom.xml index 50ccd3e90..926b2533e 100755 --- a/dsf-fhir/dsf-fhir-webservice-client/pom.xml +++ b/dsf-fhir/dsf-fhir-webservice-client/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-fhir/dsf-fhir-websocket-client/pom.xml b/dsf-fhir/dsf-fhir-websocket-client/pom.xml index f433481d5..c4e07d43a 100755 --- a/dsf-fhir/dsf-fhir-websocket-client/pom.xml +++ b/dsf-fhir/dsf-fhir-websocket-client/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-fhir-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-fhir/pom.xml b/dsf-fhir/pom.xml index b367ebbaa..2af9568b4 100755 --- a/dsf-fhir/pom.xml +++ b/dsf-fhir/pom.xml @@ -7,7 +7,7 @@ dev.dsf dsf-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-tools/dsf-tools-build-info-reader/pom.xml b/dsf-tools/dsf-tools-build-info-reader/pom.xml index 2143e2a03..6fb4e2897 100644 --- a/dsf-tools/dsf-tools-build-info-reader/pom.xml +++ b/dsf-tools/dsf-tools-build-info-reader/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-tools-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-tools/dsf-tools-bundle-generator/pom.xml b/dsf-tools/dsf-tools-bundle-generator/pom.xml index e02a9594a..7d474a51a 100755 --- a/dsf-tools/dsf-tools-bundle-generator/pom.xml +++ b/dsf-tools/dsf-tools-bundle-generator/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-tools-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-tools/dsf-tools-db-migration/pom.xml b/dsf-tools/dsf-tools-db-migration/pom.xml index ddb0f7807..0e4dab890 100755 --- a/dsf-tools/dsf-tools-db-migration/pom.xml +++ b/dsf-tools/dsf-tools-db-migration/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-tools-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-tools/dsf-tools-docker-secrets-reader/pom.xml b/dsf-tools/dsf-tools-docker-secrets-reader/pom.xml index 563453c40..0716a8980 100644 --- a/dsf-tools/dsf-tools-docker-secrets-reader/pom.xml +++ b/dsf-tools/dsf-tools-docker-secrets-reader/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-tools-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-tools/dsf-tools-documentation-generator/pom.xml b/dsf-tools/dsf-tools-documentation-generator/pom.xml index 70f2a7b50..14e1ddc6c 100644 --- a/dsf-tools/dsf-tools-documentation-generator/pom.xml +++ b/dsf-tools/dsf-tools-documentation-generator/pom.xml @@ -7,7 +7,7 @@ dev.dsf dsf-tools-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-tools/dsf-tools-proxy-test/pom.xml b/dsf-tools/dsf-tools-proxy-test/pom.xml index 07e0f553c..193379d76 100755 --- a/dsf-tools/dsf-tools-proxy-test/pom.xml +++ b/dsf-tools/dsf-tools-proxy-test/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-tools-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-tools/dsf-tools-test-data-generator/pom.xml b/dsf-tools/dsf-tools-test-data-generator/pom.xml index 319ee9e5b..5deecf3c1 100755 --- a/dsf-tools/dsf-tools-test-data-generator/pom.xml +++ b/dsf-tools/dsf-tools-test-data-generator/pom.xml @@ -6,7 +6,7 @@ dev.dsf dsf-tools-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/dsf-tools/pom.xml b/dsf-tools/pom.xml index c6dd22454..27762b6c6 100755 --- a/dsf-tools/pom.xml +++ b/dsf-tools/pom.xml @@ -7,7 +7,7 @@ dev.dsf dsf-pom - 1.6.0-SNAPSHOT + 1.6.0 diff --git a/pom.xml b/pom.xml index 034b8289c..a14280c08 100755 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ dev.dsf dsf-pom - 1.6.0-SNAPSHOT + 1.6.0 pom