diff --git a/.gitignore b/.gitignore index 89681f315..ca8c581d4 100755 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,8 @@ cert/** ### # dsf-bpe ignores ### +dsf-bpe/dsf-bpe-process-api-v1/dependency-reduced-pom.xml +dsf-bpe/dsf-bpe-process-api-v1-operaton/dependency-reduced-pom.xml dsf-bpe/dsf-bpe-server-jetty/cert/*.crt dsf-bpe/dsf-bpe-server-jetty/cert/*.key dsf-bpe/dsf-bpe-server-jetty/conf/config.properties @@ -52,6 +54,7 @@ dsf-docker-dev-setup/bpe/secrets/ca_chain.crt dsf-docker-dev-setup/bpe/secrets/issuing_ca.crt dsf-docker-dev-setup/bpe/secrets/root_ca.crt dsf-docker-dev-setup/bpe/.env +dsf-docker-dev-setup/bpe/docker-compose.override.yml dsf-docker-dev-setup/fhir/log/*.log dsf-docker-dev-setup/fhir/log/*.log.gz @@ -63,6 +66,7 @@ dsf-docker-dev-setup/fhir/secrets/fhir.key.plain dsf-docker-dev-setup/fhir/secrets/issuing_ca.crt dsf-docker-dev-setup/fhir/secrets/root_ca.crt dsf-docker-dev-setup/fhir/.env +dsf-docker-dev-setup/fhir/docker-compose.override.yml ### # dsf-docker-dev-setup-3dic-ttp ignores diff --git a/dsf-bpe/dsf-bpe-process-api-v1-base/pom.xml b/dsf-bpe/dsf-bpe-process-api-v1-base/pom.xml new file mode 100644 index 000000000..f00f8c3d8 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-api-v1-base/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + dsf-bpe-process-api-v1-base + + + dev.dsf + dsf-bpe-pom + 2.0.0-SNAPSHOT + + + + ${project.parent.parent.basedir} + + + DSF BPE Process API v1 (Base) + + + + ca.uhn.hapi.fhir + hapi-fhir-structures-r4 + ${hapi.fhir.version.v1} + + + org.springframework + spring-context + + + com.fasterxml.jackson.core + jackson-databind + + + com.sun.mail + jakarta.mail + + + jakarta.ws.rs-api + jakarta.ws.rs + + + + + org.springframework + spring-web + true + + + de.hs-heilbronn.mi + crypto-utils + ${crypto-utils.version.v1} + true + + + ca.uhn.hapi.fhir + hapi-fhir-validation + ${hapi.fhir.version.v1} + true + + + commons-logging + commons-logging + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + true + + + + + \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/ProcessPluginDefinition.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/ProcessPluginDefinition.java similarity index 96% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/ProcessPluginDefinition.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/ProcessPluginDefinition.java index 350b67668..37c6aec49 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/ProcessPluginDefinition.java +++ b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/ProcessPluginDefinition.java @@ -29,9 +29,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Scope; -import dev.dsf.bpe.v1.activity.AbstractServiceDelegate; -import dev.dsf.bpe.v1.activity.AbstractTaskMessageSend; -import dev.dsf.bpe.v1.activity.DefaultUserTaskListener; import dev.dsf.bpe.v1.documentation.ProcessDocumentation; /** @@ -146,9 +143,9 @@ default LocalDate getResourceReleaseDate() * plugin also add the {@link ProcessDocumentation} annotation. * * @return {@link Configuration} annotated classes, defining {@link Bean} annotated factory methods - * @see AbstractServiceDelegate - * @see AbstractTaskMessageSend - * @see DefaultUserTaskListener + * @see dev.dsf.bpe.v1.activity.AbstractServiceDelegate + * @see dev.dsf.bpe.v1.activity.AbstractTaskMessageSend + * @see dev.dsf.bpe.v1.activity.DefaultUserTaskListener * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE */ List> getSpringConfigurations(); diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/ProcessPluginDeploymentStateListener.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/ProcessPluginDeploymentStateListener.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/ProcessPluginDeploymentStateListener.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/ProcessPluginDeploymentStateListener.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/config/ProxyConfig.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/config/ProxyConfig.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/config/ProxyConfig.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/config/ProxyConfig.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/constants/BpmnExecutionVariables.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/constants/BpmnExecutionVariables.java similarity index 64% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/constants/BpmnExecutionVariables.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/constants/BpmnExecutionVariables.java index 7deb06fb5..2f1d9c761 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/constants/BpmnExecutionVariables.java +++ b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/constants/BpmnExecutionVariables.java @@ -15,14 +15,12 @@ */ package dev.dsf.bpe.v1.constants; -import dev.dsf.bpe.v1.activity.AbstractTaskMessageSend; import dev.dsf.bpe.v1.variables.Target; -import dev.dsf.bpe.v1.variables.Variables; /** * Defines names of standard process engine variables used by the bpe * - * @see Variables + * @see dev.dsf.bpe.v1.variables.Variables */ public final class BpmnExecutionVariables { @@ -31,13 +29,13 @@ private BpmnExecutionVariables() } /** - * Values from the target variable are used to configure {@link AbstractTaskMessageSend} activities for - * sending Task resource messages + * Values from the target variable are used to configure + * {@link dev.dsf.bpe.v1.activity.AbstractTaskMessageSend} activities for sending Task resource messages * - * @see Variables#createTarget(String, String, String, String) - * @see Variables#createTarget(String, String, String) - * @see Variables#setTarget(dev.dsf.bpe.v1.variables.Target) - * @see Variables#getTarget() + * @see dev.dsf.bpe.v1.variables.Variables#createTarget(String, String, String, String) + * @see dev.dsf.bpe.v1.variables.Variables#createTarget(String, String, String) + * @see dev.dsf.bpe.v1.variables.Variables#setTarget(dev.dsf.bpe.v1.variables.Target) + * @see dev.dsf.bpe.v1.variables.Variables#getTarget() */ public static final String TARGET = "target"; @@ -45,10 +43,10 @@ private BpmnExecutionVariables() * The targets variable is typically used to iterate over {@link Target} variables in multi instance * send/receive tasks or multi instance subprocesses * - * @see Variables#createTargets(java.util.List) - * @see Variables#createTargets(dev.dsf.bpe.v1.variables.Target...) - * @see Variables#setTargets(dev.dsf.bpe.v1.variables.Targets) - * @see Variables#getTargets() + * @see dev.dsf.bpe.v1.variables.Variables#createTargets(java.util.List) + * @see dev.dsf.bpe.v1.variables.Variables#createTargets(dev.dsf.bpe.v1.variables.Target...) + * @see dev.dsf.bpe.v1.variables.Variables#setTargets(dev.dsf.bpe.v1.variables.Targets) + * @see dev.dsf.bpe.v1.variables.Variables#getTargets() */ public static final String TARGETS = "targets"; @@ -63,10 +61,10 @@ private BpmnExecutionVariables() /** * Value of the alternativeBusinessKey variable is used to correlated incoming Task resource to a * waiting process instance if an alternative business-key was created for a communication target. See corresponding - * protected method in {@link AbstractTaskMessageSend} on how to create and use an alternative - * business-key. + * protected method in {@link dev.dsf.bpe.v1.activity.AbstractTaskMessageSend} on how to create and use + * an alternative business-key. * - * @see AbstractTaskMessageSend + * @see dev.dsf.bpe.v1.activity.AbstractTaskMessageSend */ public static final String ALTERNATIVE_BUSINESS_KEY = "alternativeBusinessKey"; } diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/constants/CodeSystems.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/constants/CodeSystems.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/constants/CodeSystems.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/constants/CodeSystems.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/constants/NamingSystems.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/constants/NamingSystems.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/constants/NamingSystems.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/constants/NamingSystems.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/documentation/ProcessDocumentation.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/documentation/ProcessDocumentation.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/documentation/ProcessDocumentation.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/documentation/ProcessDocumentation.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/service/EndpointProvider.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/service/EndpointProvider.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/service/EndpointProvider.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/service/EndpointProvider.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/service/FhirWebserviceClientProvider.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/service/FhirWebserviceClientProvider.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/service/FhirWebserviceClientProvider.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/service/FhirWebserviceClientProvider.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/service/MailService.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/service/MailService.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/service/MailService.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/service/MailService.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/service/OrganizationProvider.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/service/OrganizationProvider.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/service/OrganizationProvider.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/service/OrganizationProvider.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/service/QuestionnaireResponseHelper.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/service/QuestionnaireResponseHelper.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/service/QuestionnaireResponseHelper.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/service/QuestionnaireResponseHelper.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/service/TaskHelper.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/service/TaskHelper.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/service/TaskHelper.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/service/TaskHelper.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/variables/Target.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/variables/Target.java similarity index 92% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/variables/Target.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/variables/Target.java index f85d6b44a..67f73b18a 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/variables/Target.java +++ b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/variables/Target.java @@ -15,12 +15,10 @@ */ package dev.dsf.bpe.v1.variables; -import dev.dsf.bpe.v1.constants.BpmnExecutionVariables; - /** * Specifies a communication target for FHIR Task resources. * - * @see BpmnExecutionVariables#TARGET + * @see dev.dsf.bpe.v1.constants.BpmnExecutionVariables#TARGET * @see Variables#createTarget(String, String, String, String) * @see Variables#createTarget(String, String, String) * @see Targets diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/variables/Targets.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/variables/Targets.java similarity index 95% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/variables/Targets.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/variables/Targets.java index ae2448d2f..c0115fcfa 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/variables/Targets.java +++ b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/bpe/v1/variables/Targets.java @@ -18,12 +18,10 @@ import java.util.Collection; import java.util.List; -import dev.dsf.bpe.v1.constants.BpmnExecutionVariables; - /** * Specifies a list of communication targets for FHIR Task resources. * - * @see BpmnExecutionVariables#TARGETS + * @see dev.dsf.bpe.v1.constants.BpmnExecutionVariables#TARGETS * @see Variables#createTargets(List) * @see Variables#createTargets(Target...) * @see Target diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/common/auth/DsfOpenIdCredentials.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/common/auth/DsfOpenIdCredentials.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/common/auth/DsfOpenIdCredentials.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/common/auth/DsfOpenIdCredentials.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/common/auth/conf/DsfRole.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/common/auth/conf/DsfRole.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/common/auth/conf/DsfRole.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/common/auth/conf/DsfRole.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/common/auth/conf/Identity.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/common/auth/conf/Identity.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/common/auth/conf/Identity.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/common/auth/conf/Identity.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/common/auth/conf/OrganizationIdentity.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/common/auth/conf/OrganizationIdentity.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/common/auth/conf/OrganizationIdentity.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/common/auth/conf/OrganizationIdentity.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/common/auth/conf/PractitionerIdentity.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/common/auth/conf/PractitionerIdentity.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/common/auth/conf/PractitionerIdentity.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/common/auth/conf/PractitionerIdentity.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/All.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/All.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/All.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/All.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/Organization.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/Organization.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/Organization.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/Organization.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/ProcessAuthorizationHelper.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/ProcessAuthorizationHelper.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/ProcessAuthorizationHelper.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/ProcessAuthorizationHelper.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/ProcessAuthorizationHelperImpl.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/ProcessAuthorizationHelperImpl.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/ProcessAuthorizationHelperImpl.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/ProcessAuthorizationHelperImpl.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/Recipient.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/Recipient.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/Recipient.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/Recipient.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/Requester.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/Requester.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/Requester.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/Requester.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/Role.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/Role.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/Role.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/Role.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/WithAuthorization.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/WithAuthorization.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/process/WithAuthorization.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/process/WithAuthorization.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/read/ReadAccessHelper.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/read/ReadAccessHelper.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/authorization/read/ReadAccessHelper.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/authorization/read/ReadAccessHelper.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/BasicFhirWebserviceClient.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/BasicFhirWebserviceClient.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/BasicFhirWebserviceClient.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/BasicFhirWebserviceClient.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/FhirWebserviceClient.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/FhirWebserviceClient.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/FhirWebserviceClient.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/FhirWebserviceClient.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/PreferReturnMinimal.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/PreferReturnMinimal.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/PreferReturnMinimal.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/PreferReturnMinimal.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/PreferReturnMinimalWithRetry.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/PreferReturnMinimalWithRetry.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/PreferReturnMinimalWithRetry.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/PreferReturnMinimalWithRetry.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/PreferReturnOutcome.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/PreferReturnOutcome.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/PreferReturnOutcome.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/PreferReturnOutcome.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/PreferReturnOutcomeWithRetry.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/PreferReturnOutcomeWithRetry.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/PreferReturnOutcomeWithRetry.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/PreferReturnOutcomeWithRetry.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/PreferReturnResource.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/PreferReturnResource.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/PreferReturnResource.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/PreferReturnResource.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/RetryClient.java b/dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/RetryClient.java similarity index 100% rename from dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/fhir/client/RetryClient.java rename to dsf-bpe/dsf-bpe-process-api-v1-base/src/main/java/dev/dsf/fhir/client/RetryClient.java diff --git a/dsf-bpe/dsf-bpe-process-api-v1-impl/pom.xml b/dsf-bpe/dsf-bpe-process-api-v1-impl/pom.xml index badea9901..abe5b4941 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1-impl/pom.xml +++ b/dsf-bpe/dsf-bpe-process-api-v1-impl/pom.xml @@ -39,7 +39,7 @@ dev.dsf - dsf-bpe-process-api-v1 + dsf-bpe-process-api-v1-operaton @@ -117,7 +117,7 @@ dev.dsf - dsf-bpe-process-api-v1 + dsf-bpe-process-api-v1-operaton dev.dsf diff --git a/dsf-bpe/dsf-bpe-process-api-v1-impl/src/main/java/dev/dsf/bpe/v1/plugin/ProcessPluginClassLoader.java b/dsf-bpe/dsf-bpe-process-api-v1-impl/src/main/java/dev/dsf/bpe/v1/plugin/ProcessPluginClassLoader.java index 385c522fd..e81fe52e2 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1-impl/src/main/java/dev/dsf/bpe/v1/plugin/ProcessPluginClassLoader.java +++ b/dsf-bpe/dsf-bpe-process-api-v1-impl/src/main/java/dev/dsf/bpe/v1/plugin/ProcessPluginClassLoader.java @@ -98,7 +98,14 @@ public void visitFieldInsn(int opcode, String owner, String name, String descrip public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) { - super.visitMethodInsn(opcode, replace(owner), name, replace(descriptor), isInterface); + if ((FROM_PACKAGE + "/model/bpmn/instance/UserTask").equals(owner) + && "getCamundaFormKey".equals(name) && "()Ljava/lang/String;".equals(descriptor)) + { + super.visitMethodInsn(opcode, TO_PACKAGE + "/bpm/model/bpmn/instance/UserTask", + "getOperatonFormKey", "()Ljava/lang/String;", isInterface); + } + else + super.visitMethodInsn(opcode, replace(owner), name, replace(descriptor), isInterface); } @Override diff --git a/dsf-bpe/dsf-bpe-process-api-v1-operaton/pom.xml b/dsf-bpe/dsf-bpe-process-api-v1-operaton/pom.xml new file mode 100644 index 000000000..0968582e8 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-api-v1-operaton/pom.xml @@ -0,0 +1,123 @@ + + + 4.0.0 + + dsf-bpe-process-api-v1-operaton + + + dev.dsf + dsf-bpe-pom + 2.0.0-SNAPSHOT + + + + ${project.parent.parent.basedir} + + + DSF BPE Process API v1 (Operaton) + + + + dev.dsf + dsf-bpe-process-api-v1-base + + + ca.uhn.hapi.fhir + hapi-fhir-structures-r4 + ${hapi.fhir.version.v1} + + + org.operaton.bpm + operaton-engine + + + org.springframework + spring-context + + + com.fasterxml.jackson.core + jackson-databind + + + com.sun.mail + jakarta.mail + + + jakarta.ws.rs-api + jakarta.ws.rs + + + + + org.springframework + spring-web + true + + + de.hs-heilbronn.mi + crypto-utils + ${crypto-utils.version.v1} + true + + + ca.uhn.hapi.fhir + hapi-fhir-validation + ${hapi.fhir.version.v1} + true + + + commons-logging + commons-logging + + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + + + dev.dsf:dsf-bpe-process-api-v1-base + + + true + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + src/main/java;../dsf-bpe-process-api-v1-base/src/main/java + + + + + \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/ProcessPluginApi.java b/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/ProcessPluginApi.java new file mode 100644 index 000000000..ff1df272e --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/ProcessPluginApi.java @@ -0,0 +1,67 @@ +/* + * Copyright 2018-2025 Heilbronn University of Applied Sciences + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * 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. + */ +package dev.dsf.bpe.v1; + +import org.operaton.bpm.engine.delegate.DelegateExecution; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import ca.uhn.fhir.context.FhirContext; +import dev.dsf.bpe.v1.config.ProxyConfig; +import dev.dsf.bpe.v1.service.EndpointProvider; +import dev.dsf.bpe.v1.service.FhirWebserviceClientProvider; +import dev.dsf.bpe.v1.service.MailService; +import dev.dsf.bpe.v1.service.OrganizationProvider; +import dev.dsf.bpe.v1.service.QuestionnaireResponseHelper; +import dev.dsf.bpe.v1.service.TaskHelper; +import dev.dsf.bpe.v1.variables.Variables; +import dev.dsf.fhir.authorization.process.ProcessAuthorizationHelper; +import dev.dsf.fhir.authorization.read.ReadAccessHelper; + +/** + * Gives access to services available to process plugins. This api and all services excepted {@link Variables} can be + * injected using {@link Autowired} into spring {@link Configuration} classes. + * + * @see ProcessPluginDefinition#getSpringConfigurations() + */ +public interface ProcessPluginApi +{ + ProxyConfig getProxyConfig(); + + EndpointProvider getEndpointProvider(); + + FhirContext getFhirContext(); + + FhirWebserviceClientProvider getFhirWebserviceClientProvider(); + + MailService getMailService(); + + ObjectMapper getObjectMapper(); + + OrganizationProvider getOrganizationProvider(); + + ProcessAuthorizationHelper getProcessAuthorizationHelper(); + + QuestionnaireResponseHelper getQuestionnaireResponseHelper(); + + ReadAccessHelper getReadAccessHelper(); + + TaskHelper getTaskHelper(); + + Variables getVariables(DelegateExecution execution); +} diff --git a/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/activity/AbstractServiceDelegate.java b/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/activity/AbstractServiceDelegate.java new file mode 100644 index 000000000..14945f276 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/activity/AbstractServiceDelegate.java @@ -0,0 +1,171 @@ +/* + * Copyright 2018-2025 Heilbronn University of Applied Sciences + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * 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. + */ +package dev.dsf.bpe.v1.activity; + +import java.util.List; +import java.util.Objects; + +import org.hl7.fhir.r4.model.CodeableConcept; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.Task.TaskOutputComponent; +import org.hl7.fhir.r4.model.Task.TaskStatus; +import org.operaton.bpm.engine.delegate.BpmnError; +import org.operaton.bpm.engine.delegate.DelegateExecution; +import org.operaton.bpm.engine.delegate.JavaDelegate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import dev.dsf.bpe.v1.ProcessPluginApi; +import dev.dsf.bpe.v1.ProcessPluginDefinition; +import dev.dsf.bpe.v1.constants.CodeSystems.BpmnMessage; +import dev.dsf.bpe.v1.variables.Variables; + +/** + * Abstract implementation of the {@link JavaDelegate} interface with added error handling and convenient access to + * process execution variables with the variables parameter of the + * {@link #doExecute(DelegateExecution, Variables)} method. + *

+ * Configure BPMN service tasks with an implementation of type 'Java class' with the fully qualified class name of the + * class extending this abstract implementation. + *

+ * Configure your service task implementation as a {@link Bean} in your spring {@link Configuration} class with scope + * "prototype". + * + * @see ProcessPluginDefinition#getSpringConfigurations() + */ +public abstract class AbstractServiceDelegate implements JavaDelegate, InitializingBean +{ + private static final Logger logger = LoggerFactory.getLogger(AbstractServiceDelegate.class); + + protected final ProcessPluginApi api; + + /** + * @param api + * not null + */ + public AbstractServiceDelegate(ProcessPluginApi api) + { + this.api = api; + } + + @Override + public void afterPropertiesSet() throws Exception + { + Objects.requireNonNull(api, "api"); + } + + @Override + public final void execute(DelegateExecution execution) throws Exception + { + final Variables variables = api.getVariables(execution); + + try + { + logger.trace("Execution of task with id='{}'", execution.getCurrentActivityId()); + + doExecute(execution, variables); + } + // Error boundary event, do not stop process execution + catch (BpmnError error) + { + logger.debug("Error while executing service delegate {}", getClass().getName(), error); + logger.error( + "Process {} encountered error boundary event in step {} for task {}, error-code: {}, message: {}", + execution.getProcessDefinitionId(), execution.getActivityInstanceId(), + api.getTaskHelper().getLocalVersionlessAbsoluteUrl(variables.getStartTask()), error.getErrorCode(), + error.getMessage()); + + throw error; + } + // Not an error boundary event, stop process execution + catch (Exception exception) + { + logger.debug("Error while executing service delegate {}", getClass().getName(), exception); + logger.error("Process {} has fatal error in step {} for task {}, reason: {} - {}", + execution.getProcessDefinitionId(), execution.getActivityInstanceId(), + api.getTaskHelper().getLocalVersionlessAbsoluteUrl(variables.getStartTask()), + exception.getClass().getName(), exception.getMessage()); + + String errorMessage = "Process " + execution.getProcessDefinitionId() + " has fatal error in step " + + execution.getActivityInstanceId() + ", reason: " + exception.getMessage(); + + updateFailedIfInprogress(variables.getTasks(), errorMessage); + + // TODO evaluate throwing exception as alternative to stopping the process instance + execution.getProcessEngine().getRuntimeService().deleteProcessInstance(execution.getProcessInstanceId(), + exception.getMessage()); + } + } + + /** + * Implement this method to execute custom business logic within BPMN service tasks. + * + * @param execution + * Process instance information and variables + * @param variables + * DSF process variables + * @throws BpmnError + * Thrown when an error boundary event should be called + * @throws Exception + * Uncaught exceptions thrown by this method will result in Task status failed for all current + * in-progress Task resource with the exception message added as an error output. An exception + * (not {@link BpmnError}) thrown by this method will also result in the process instance stopping + * execution and being deleted. + */ + protected abstract void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception; + + private void updateFailedIfInprogress(List tasks, String errorMessage) + { + for (int i = tasks.size() - 1; i >= 0; i--) + { + Task task = tasks.get(i); + + if (TaskStatus.INPROGRESS.equals(task.getStatus())) + { + task.setStatus(Task.TaskStatus.FAILED); + task.addOutput(new TaskOutputComponent(new CodeableConcept(BpmnMessage.error()), + new StringType(errorMessage))); + updateAndHandleException(task); + } + else + { + logger.debug("Not updating Task {} with status: {}", + api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), task.getStatus()); + } + } + } + + private void updateAndHandleException(Task task) + { + try + { + logger.debug("Updating Task {}, new status: {}", api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), + task.getStatus().toCode()); + + api.getFhirWebserviceClientProvider().getLocalWebserviceClient().withMinimalReturn().update(task); + } + catch (Exception e) + { + logger.debug("Unable to update Task {}", api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), e); + logger.error("Unable to update Task {}: {} - {}", api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), + e.getClass().getName(), e.getMessage()); + } + } +} diff --git a/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/activity/AbstractTaskMessageSend.java b/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/activity/AbstractTaskMessageSend.java new file mode 100644 index 000000000..ef3862e41 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/activity/AbstractTaskMessageSend.java @@ -0,0 +1,536 @@ +/* + * Copyright 2018-2025 Heilbronn University of Applied Sciences + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * 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. + */ +package dev.dsf.bpe.v1.activity; + +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.UUID; +import java.util.stream.Stream; + +import org.hl7.fhir.r4.model.CodeableConcept; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Meta; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.ResourceType; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.Task.ParameterComponent; +import org.hl7.fhir.r4.model.Task.TaskIntent; +import org.hl7.fhir.r4.model.Task.TaskOutputComponent; +import org.hl7.fhir.r4.model.Task.TaskStatus; +import org.operaton.bpm.engine.delegate.DelegateExecution; +import org.operaton.bpm.engine.delegate.JavaDelegate; +import org.operaton.bpm.engine.impl.el.FixedValue; +import org.operaton.bpm.model.bpmn.instance.EndEvent; +import org.operaton.bpm.model.bpmn.instance.IntermediateThrowEvent; +import org.operaton.bpm.model.bpmn.instance.SendTask; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import dev.dsf.bpe.v1.ProcessPluginApi; +import dev.dsf.bpe.v1.ProcessPluginDefinition; +import dev.dsf.bpe.v1.constants.BpmnExecutionVariables; +import dev.dsf.bpe.v1.constants.CodeSystems.BpmnMessage; +import dev.dsf.bpe.v1.constants.NamingSystems.OrganizationIdentifier; +import dev.dsf.bpe.v1.variables.Target; +import dev.dsf.bpe.v1.variables.Targets; +import dev.dsf.bpe.v1.variables.Variables; +import dev.dsf.fhir.client.FhirWebserviceClient; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.core.Response.StatusType; + +/** + * Base class for implementing BPMN message send tasks, intermediate message throw events and message end events using + * FHIR Task resources. Requires three String fields to be injected via BPMN: + *

    + *
  • instantiatesCanonical with the URL (including version) of the Activity to start or continue. + *
  • messageName with the with the BPMN message-name of the start event, intermediate message catch event or + * message receive task. + *
  • profile with the URL (including version) of the profile (StructureDefinition) that the Task resource used + * should conform to. + *
+ *

+ * Configure BPMN message send tasks, intermediate message throw events and message end event with an implementation of + * type 'Java class' with the fully qualified class name of the class extending this abstract implementation. + *

+ * Configure your service task implementation as a {@link Bean} in your spring {@link Configuration} class with scope + * "prototype". + * + * @see ProcessPluginDefinition#getSpringConfigurations() + */ +public abstract class AbstractTaskMessageSend implements JavaDelegate, InitializingBean +{ + private static final Logger logger = LoggerFactory.getLogger(AbstractTaskMessageSend.class); + + protected final ProcessPluginApi api; + + // set via field injection + private FixedValue instantiatesCanonical; + private FixedValue messageName; + private FixedValue profile; + + /** + * @param api + * not null + */ + public AbstractTaskMessageSend(ProcessPluginApi api) + { + this.api = api; + } + + @Override + public void afterPropertiesSet() throws Exception + { + Objects.requireNonNull(api, "api"); + } + + /** + * @param instantiatesCanonical + * not null + * @deprecated only for process engine field injection + */ + @Deprecated + public final void setInstantiatesCanonical(FixedValue instantiatesCanonical) + { + this.instantiatesCanonical = instantiatesCanonical; + } + + /** + * Retrieves the instantiatesCanonical value used for Task resources send by this class via the injected field + * instantiatesCanonical. + *

+ * Override this method to use a different mechanism for retrieving the value for instantiatesCanonical. For + * example via a process variable. Note: A non empty value e.g 'disable' still needs to be injected in the BPMN file + * in order to comply with the validation performed during plugin loading. + * + * @param execution + * not null + * @param variables + * not null + * @return instantiatesCanonical value used for Task resources send by this class + */ + protected String getInstantiatesCanonical(DelegateExecution execution, Variables variables) + { + return instantiatesCanonical == null ? null : instantiatesCanonical.getExpressionText(); + } + + /** + * @param messageName + * not null + * @deprecated only for process engine field injection + */ + @Deprecated + public final void setMessageName(FixedValue messageName) + { + this.messageName = messageName; + } + + /** + * Retrieves the messageName value used for Task resources send by this class via the injected field + * messageName. + *

+ * Override this method to use a different mechanism for retrieving the value for messageName. For example via a + * process variable. Note: A non empty value e.g 'disable' still needs to be injected in the BPMN file in order to + * comply with the validation performed during plugin loading. + * + * @param execution + * not null + * @param variables + * not null + * @return messageName value used for Task resources send by this class + */ + protected String getMessageName(DelegateExecution execution, Variables variables) + { + return messageName == null ? null : messageName.getExpressionText(); + } + + /** + * @param profile + * not null + * @deprecated only for process engine field injection + */ + @Deprecated + public final void setProfile(FixedValue profile) + { + this.profile = profile; + } + + /** + * Retrieves the profile value used for Task resources send by this class via the injected field profile. + *

+ * Override this method to use a different mechanism for retrieving the value for profile. For example via a + * process variable. Note: A non empty value e.g 'disable' still needs to be injected in the BPMN file in order to + * comply with the validation performed during plugin loading. + * + * @param execution + * not null + * @param variables + * not null + * @return profile value used for Task resources send by this class + */ + protected String getProfile(DelegateExecution execution, Variables variables) + { + return profile == null ? null : profile.getExpressionText(); + } + + @Override + public final void execute(DelegateExecution execution) throws Exception + { + doExecute(execution, api.getVariables(execution)); + } + + protected void doExecute(DelegateExecution execution, Variables variables) throws Exception + { + final String instantiatesCanonical = getInstantiatesCanonical(execution, variables); + final String messageName = getMessageName(execution, variables); + final String profile = getProfile(execution, variables); + final String businessKey = execution.getBusinessKey(); + final Target target = variables.getTarget(); + + try + { + sendTask(execution, variables, target, instantiatesCanonical, messageName, businessKey, profile, + getAdditionalInputParameters(execution, variables)); + } + catch (Exception e) + { + String exceptionMessage = e.getMessage(); + if (e instanceof WebApplicationException w && (e.getMessage() == null || e.getMessage().isBlank())) + { + StatusType statusInfo = w.getResponse().getStatusInfo(); + exceptionMessage = statusInfo.getStatusCode() + " " + statusInfo.getReasonPhrase(); + } + + logger.debug("Error while sending Task", e); + String errorMessage = "Task " + instantiatesCanonical + " send failed [recipient: " + + target.getOrganizationIdentifierValue() + ", endpoint: " + target.getEndpointIdentifierValue() + + ", businessKey: " + businessKey + + (target.getCorrelationKey() == null ? "" : ", correlationKey: " + target.getCorrelationKey()) + + ", message: " + messageName + ", error: " + e.getClass().getName() + " - " + exceptionMessage + + "]"; + logger.warn(errorMessage); + + if (execution.getBpmnModelElementInstance() instanceof IntermediateThrowEvent) + handleIntermediateThrowEventError(execution, variables, e, errorMessage); + else if (execution.getBpmnModelElementInstance() instanceof EndEvent) + handleEndEventError(execution, variables, e, errorMessage); + else if (execution.getBpmnModelElementInstance() instanceof SendTask) + handleSendTaskError(execution, variables, e, errorMessage); + else + logger.warn("Error handling for {} not implemented", + execution.getBpmnModelElementInstance().getClass().getName()); + } + } + + protected void handleIntermediateThrowEventError(DelegateExecution execution, Variables variables, + Exception exception, String errorMessage) + { + logger.debug("Error while executing Task message send {}", getClass().getName(), exception); + logger.error("Process {} has fatal error in step {} for task {}, reason: {} - {}", + execution.getProcessDefinitionId(), execution.getActivityInstanceId(), + api.getTaskHelper().getLocalVersionlessAbsoluteUrl(variables.getStartTask()), + exception.getClass().getName(), exception.getMessage()); + + updateFailedIfInprogress(variables.getTasks(), errorMessage); + + execution.getProcessEngine().getRuntimeService().deleteProcessInstance(execution.getProcessInstanceId(), + exception.getMessage()); + } + + protected void handleEndEventError(DelegateExecution execution, Variables variables, Exception exception, + String errorMessage) + { + logger.debug("Error while executing Task message send {}", getClass().getName(), exception); + logger.error("Process {} has fatal error in step {} for task {}, reason: {} - {}", + execution.getProcessDefinitionId(), execution.getActivityInstanceId(), + api.getTaskHelper().getLocalVersionlessAbsoluteUrl(variables.getStartTask()), + exception.getClass().getName(), exception.getMessage()); + + updateFailedIfInprogress(variables.getTasks(), errorMessage); + + // End event: No need to delete process instance + } + + protected void handleSendTaskError(DelegateExecution execution, Variables variables, Exception exception, + String errorMessage) + { + Targets targets = variables.getTargets(); + + // if we are a multi instance message send task, remove target + if (targets != null && !targets.isEmpty()) + { + Target target = variables.getTarget(); + targets = targets.removeByEndpointIdentifierValue(target); + variables.setTargets(targets); + + addErrorIfInprogress(variables.getTasks(), errorMessage); + + logger.debug("Target organization {}, endpoint {} with error {} removed from target list", + target.getOrganizationIdentifierValue(), target.getEndpointIdentifierValue(), + exception.getMessage()); + } + + // if we are not a multi instance message send task or all sends have failed (targets emtpy) + else + { + logger.debug("Error while executing Task message send {}", getClass().getName(), exception); + logger.error("Process {} has fatal error in step {} for task {}, last reason: {} - {}", + execution.getProcessDefinitionId(), execution.getActivityInstanceId(), + api.getTaskHelper().getLocalVersionlessAbsoluteUrl(variables.getStartTask()), + exception.getClass().getName(), exception.getMessage()); + + updateFailedIfInprogress(variables.getTasks(), errorMessage); + + execution.getProcessEngine().getRuntimeService().deleteProcessInstance(execution.getProcessInstanceId(), + exception.getMessage()); + } + } + + private void addErrorIfInprogress(List tasks, String errorMessage) + { + for (int i = tasks.size() - 1; i >= 0; i--) + { + Task task = tasks.get(i); + + if (TaskStatus.INPROGRESS.equals(task.getStatus())) + { + addErrorMessage(task, errorMessage); + } + else + { + logger.debug("Not adding error to Task {} with status: {}", + api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), task.getStatus()); + } + } + } + + private void updateFailedIfInprogress(List tasks, String errorMessage) + { + for (int i = tasks.size() - 1; i >= 0; i--) + { + Task task = tasks.get(i); + + if (TaskStatus.INPROGRESS.equals(task.getStatus())) + { + task.setStatus(Task.TaskStatus.FAILED); + addErrorMessage(task, errorMessage); + updateAndHandleException(task); + } + else + { + logger.debug("Not updating Task {} with status: {}", + api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), task.getStatus()); + } + } + } + + protected void addErrorMessage(Task task, String errorMessage) + { + task.addOutput(new TaskOutputComponent(new CodeableConcept(BpmnMessage.error()), new StringType(errorMessage))); + } + + private void updateAndHandleException(Task task) + { + try + { + logger.debug("Updating Task {}, new status: {}", api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), + task.getStatus().toCode()); + + api.getFhirWebserviceClientProvider().getLocalWebserviceClient().withMinimalReturn().update(task); + } + catch (Exception e) + { + logger.debug("Unable to update Task {}", api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), e); + logger.error("Unable to update Task {}: {} - {}", api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), + e.getClass().getName(), e.getMessage()); + } + } + + /** + * Override this method to add additional input parameters to the task resource being send. + * + * @param execution + * the delegate execution of this process instance + * @return {@link Stream} of {@link ParameterComponent}s to be added as input parameters + */ + protected Stream getAdditionalInputParameters(DelegateExecution execution, Variables variables) + { + return Stream.empty(); + } + + /** + * Generates an alternative business-key and stores it as a process variable with name + * {@link BpmnExecutionVariables#ALTERNATIVE_BUSINESS_KEY} + *

+ * Use this method in combination with overriding + * {@link #sendTask(DelegateExecution, Variables, Target, String, String, String, String, Stream)} to use an + * alternative business-key with the communication target. + * + *

+	 * @Override
+	 * protected void sendTasksendTask(DelegateExecution execution, Variables variables, Target target,
+	 * 		String instantiatesCanonical, String messageName, String businessKey, String profile,
+	 * 		Stream<ParameterComponent> additionalInputParameters)
+	 * {
+	 * 	String alternativeBusinesKey = createAndSaveAlternativeBusinessKey();
+	 * 	super.sendTask(execution, target, instantiatesUri, messageName, alternativeBusinesKey, profile,
+	 * 			additionalInputParameters);
+	 * }
+	 * 
+ * + * Return tasks from the target using the alternative business-key will correlate with this process instance. + *

+ * + * + * @param execution + * not null + * @return the alternative business-key stored as variable {@link BpmnExecutionVariables#ALTERNATIVE_BUSINESS_KEY} + * @see Variables#setAlternativeBusinessKey(String) + */ + protected final String createAndSaveAlternativeBusinessKey(DelegateExecution execution, Variables variables) + { + String alternativeBusinessKey = UUID.randomUUID().toString(); + variables.setAlternativeBusinessKey(alternativeBusinessKey); + return alternativeBusinessKey; + } + + /** + * @param execution + * not null + * @param variables + * not null + * @param target + * not null + * @param instantiatesCanonical + * not null, not empty + * @param messageName + * not null, not empty + * @param businessKey + * not null, not empty + * @param profile + * not null, not empty + * @param additionalInputParameters + * may be null + */ + protected void sendTask(DelegateExecution execution, Variables variables, Target target, + String instantiatesCanonical, String messageName, String businessKey, String profile, + Stream additionalInputParameters) + { + Objects.requireNonNull(target, "target"); + Objects.requireNonNull(instantiatesCanonical, "instantiatesCanonical"); + if (instantiatesCanonical.isEmpty()) + throw new IllegalArgumentException("instantiatesCanonical empty"); + Objects.requireNonNull(messageName, "messageName"); + if (messageName.isEmpty()) + throw new IllegalArgumentException("messageName empty"); + Objects.requireNonNull(businessKey, "businessKey"); + if (businessKey.isEmpty()) + throw new IllegalArgumentException("profile empty"); + Objects.requireNonNull(profile, "profile"); + if (profile.isEmpty()) + throw new IllegalArgumentException("profile empty"); + + Task task = new Task(); + task.setMeta(new Meta().addProfile(profile)); + task.setStatus(TaskStatus.REQUESTED); + task.setIntent(TaskIntent.ORDER); + task.setAuthoredOn(new Date()); + task.setRequester(getRequester()); + task.getRestriction().addRecipient(getRecipient(target)); + task.setInstantiatesCanonical(instantiatesCanonical); + + ParameterComponent messageNameInput = new ParameterComponent(new CodeableConcept(BpmnMessage.messageName()), + new StringType(messageName)); + task.getInput().add(messageNameInput); + + ParameterComponent businessKeyInput = new ParameterComponent(new CodeableConcept(BpmnMessage.businessKey()), + new StringType(businessKey)); + task.getInput().add(businessKeyInput); + + String correlationKey = target.getCorrelationKey(); + if (correlationKey != null) + { + ParameterComponent correlationKeyInput = new ParameterComponent( + new CodeableConcept(BpmnMessage.correlationKey()), new StringType(correlationKey)); + task.getInput().add(correlationKeyInput); + } + + if (additionalInputParameters != null) + additionalInputParameters.forEach(task.getInput()::add); + + FhirWebserviceClient client = api.getFhirWebserviceClientProvider() + .getWebserviceClient(target.getEndpointUrl()); + + if (correlationKey != null) + logger.info( + "Sending task {} [recipient: {}, endpoint: {}, businessKey: {}, correlationKey: {}, message: {}] ...", + task.getInstantiatesCanonical(), target.getOrganizationIdentifierValue(), + target.getEndpointIdentifierValue(), businessKey, correlationKey, messageName); + else + logger.info("Sending task {} [recipient: {}, endpoint: {}, businessKey: {}, message: {}] ...", + task.getInstantiatesCanonical(), target.getOrganizationIdentifierValue(), + target.getEndpointIdentifierValue(), businessKey, messageName); + + logger.trace("Task resource to send: {}", + api.getFhirContext().newJsonParser().setStripVersionsFromReferences(false) + .setOverrideResourceIdWithBundleEntryFullUrl(false).encodeResourceToString(task)); + + IdType created = doSend(client, task); + + logger.info("Task {} send [task: {}]", task.getInstantiatesCanonical(), created.toVersionless().getValue()); + } + + /** + * Override this method to modify the remote task create behavior, e.g. to implement retries + * + *

+	 * 
+	 * @Override
+	 * protected void doSend(FhirWebserviceClient client, Task task)
+	 * {
+	 *     client.withMinimalReturn().withRetry(2).create(task);
+	 * }
+	 * 
+	 * 
+ * + * @param client + * not null + * @param task + * not null + * @return id of created task + */ + protected IdType doSend(FhirWebserviceClient client, Task task) + { + return client.withMinimalReturn().create(task); + } + + protected Reference getRecipient(Target target) + { + return new Reference().setType(ResourceType.Organization.name()) + .setIdentifier(OrganizationIdentifier.withValue(target.getOrganizationIdentifierValue())); + } + + protected Reference getRequester() + { + return new Reference().setType(ResourceType.Organization.name()) + .setIdentifier(api.getOrganizationProvider().getLocalOrganizationIdentifier() + .orElseThrow(() -> new IllegalStateException("Local organization identifier unknown"))); + } +} diff --git a/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/activity/DefaultUserTaskListener.java b/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/activity/DefaultUserTaskListener.java new file mode 100644 index 000000000..04b9c7e49 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/activity/DefaultUserTaskListener.java @@ -0,0 +1,276 @@ +/* + * Copyright 2018-2025 Heilbronn University of Applied Sciences + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * 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. + */ +package dev.dsf.bpe.v1.activity; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.CodeableConcept; +import org.hl7.fhir.r4.model.Questionnaire; +import org.hl7.fhir.r4.model.QuestionnaireResponse; +import org.hl7.fhir.r4.model.Reference; +import org.hl7.fhir.r4.model.ResourceType; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.model.Task; +import org.hl7.fhir.r4.model.Task.TaskOutputComponent; +import org.hl7.fhir.r4.model.Task.TaskStatus; +import org.hl7.fhir.r4.model.Type; +import org.operaton.bpm.engine.delegate.DelegateExecution; +import org.operaton.bpm.engine.delegate.DelegateTask; +import org.operaton.bpm.engine.delegate.TaskListener; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.annotation.Bean; + +import dev.dsf.bpe.v1.ProcessPluginApi; +import dev.dsf.bpe.v1.constants.CodeSystems.BpmnMessage; +import dev.dsf.bpe.v1.constants.CodeSystems.BpmnUserTask; +import dev.dsf.bpe.v1.variables.Variables; + +/** + * Default {@link TaskListener} implementation. This listener will be added to user tasks if no other + * {@link TaskListener} is defined for the 'create' event type. + *

+ * BPMN user tasks need to define the form to be used with type 'Embedded or External Task Forms' and the canonical URL + * of the a {@link Questionnaire} resource as the form key. + *

+ * To modify the behavior of the listener, for example to set default values in the created 'in-progress' + * {@link QuestionnaireResponse}, extend this class, register it as a prototype {@link Bean} and specify the class name + * as a task listener with event type 'create' in the BPMN. + */ +public class DefaultUserTaskListener implements TaskListener, InitializingBean +{ + private static final Logger logger = LoggerFactory.getLogger(DefaultUserTaskListener.class); + + private final ProcessPluginApi api; + + /** + * @param api + * not null + */ + public DefaultUserTaskListener(ProcessPluginApi api) + { + this.api = api; + } + + @Override + public void afterPropertiesSet() throws Exception + { + Objects.requireNonNull(api, "api"); + } + + @Override + public final void notify(DelegateTask userTask) + { + final DelegateExecution execution = userTask.getExecution(); + final Variables variables = api.getVariables(execution); + + try + { + logger.trace("Execution of user task with id='{}'", execution.getCurrentActivityId()); + + String questionnaireUrlWithVersion = userTask.getBpmnModelElementInstance().getOperatonFormKey(); + Questionnaire questionnaire = readQuestionnaire(questionnaireUrlWithVersion); + + String businessKey = execution.getBusinessKey(); + String userTaskId = userTask.getId(); + + QuestionnaireResponse questionnaireResponse = createDefaultQuestionnaireResponse( + questionnaireUrlWithVersion, businessKey, userTaskId); + transformQuestionnaireItemsToQuestionnaireResponseItems(questionnaireResponse, questionnaire); + + beforeQuestionnaireResponseCreate(userTask, questionnaireResponse); + checkQuestionnaireResponse(questionnaireResponse); + + QuestionnaireResponse created = api.getFhirWebserviceClientProvider().getLocalWebserviceClient() + .withRetryForever(60000).create(questionnaireResponse); + + logger.info("Created QuestionnaireResponse for user task at {}, process waiting for it's completion", + api.getQuestionnaireResponseHelper().getLocalVersionlessAbsoluteUrl(created)); + + afterQuestionnaireResponseCreate(userTask, created); + } + catch (Exception exception) + { + logger.debug("Error while executing user task listener {}", getClass().getName(), exception); + logger.error("Process {} has fatal error in step {} for task {}, reason: {} - {}", + execution.getProcessDefinitionId(), execution.getActivityInstanceId(), + api.getTaskHelper().getLocalVersionlessAbsoluteUrl(variables.getStartTask()), + exception.getClass().getName(), exception.getMessage()); + + String errorMessage = "Process " + execution.getProcessDefinitionId() + " has fatal error in step " + + execution.getActivityInstanceId() + ", reason: " + exception.getMessage(); + + updateFailedIfInprogress(variables.getTasks(), errorMessage); + + execution.getProcessEngine().getRuntimeService().deleteProcessInstance(execution.getProcessInstanceId(), + exception.getMessage()); + } + } + + private Questionnaire readQuestionnaire(String urlWithVersion) + { + Bundle search = api.getFhirWebserviceClientProvider().getLocalWebserviceClient().search(Questionnaire.class, + Map.of("url", Collections.singletonList(urlWithVersion))); + + List questionnaires = search.getEntry().stream().filter(Bundle.BundleEntryComponent::hasResource) + .map(Bundle.BundleEntryComponent::getResource).filter(r -> r instanceof Questionnaire) + .map(r -> (Questionnaire) r).collect(Collectors.toList()); + + if (questionnaires.size() < 1) + throw new RuntimeException("Could not find Questionnaire resource with url|version=" + urlWithVersion); + + if (questionnaires.size() > 1) + logger.info("Found {} Questionnaire resources with url|version={}, using the first", questionnaires.size(), + urlWithVersion); + + return questionnaires.get(0); + } + + private QuestionnaireResponse createDefaultQuestionnaireResponse(String questionnaireUrlWithVersion, + String businessKey, String userTaskId) + { + QuestionnaireResponse questionnaireResponse = new QuestionnaireResponse(); + questionnaireResponse.setQuestionnaire(questionnaireUrlWithVersion); + questionnaireResponse.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.INPROGRESS); + + questionnaireResponse.setAuthor(new Reference().setType(ResourceType.Organization.name()) + .setIdentifier(api.getOrganizationProvider().getLocalOrganizationIdentifier() + .orElseThrow(() -> new IllegalStateException("Local organization identifier unknown")))); + + api.getQuestionnaireResponseHelper().addItemLeafWithAnswer(questionnaireResponse, + BpmnUserTask.Codes.BUSINESS_KEY, "The business-key of the process execution", + new StringType(businessKey)); + + api.getQuestionnaireResponseHelper().addItemLeafWithAnswer(questionnaireResponse, + BpmnUserTask.Codes.USER_TASK_ID, "The user-task-id of the process execution", + new StringType(userTaskId)); + + return questionnaireResponse; + } + + private void transformQuestionnaireItemsToQuestionnaireResponseItems(QuestionnaireResponse questionnaireResponse, + Questionnaire questionnaire) + { + questionnaire.getItem().stream().filter(i -> !BpmnUserTask.Codes.BUSINESS_KEY.equals(i.getLinkId())) + .filter(i -> !BpmnUserTask.Codes.USER_TASK_ID.equals(i.getLinkId())) + .forEach(i -> transformItem(questionnaireResponse, i)); + } + + private void transformItem(QuestionnaireResponse questionnaireResponse, + Questionnaire.QuestionnaireItemComponent question) + { + if (Questionnaire.QuestionnaireItemType.DISPLAY.equals(question.getType())) + { + api.getQuestionnaireResponseHelper().addItemLeafWithoutAnswer(questionnaireResponse, question.getLinkId(), + question.getText()); + } + else + { + Type answer = api.getQuestionnaireResponseHelper().transformQuestionTypeToAnswerType(question); + api.getQuestionnaireResponseHelper().addItemLeafWithAnswer(questionnaireResponse, question.getLinkId(), + question.getText(), answer); + } + } + + private void checkQuestionnaireResponse(QuestionnaireResponse questionnaireResponse) + { + questionnaireResponse.getItem().stream().filter(i -> BpmnUserTask.Codes.BUSINESS_KEY.equals(i.getLinkId())) + .findFirst() + .orElseThrow(() -> new RuntimeException("QuestionnaireResponse does not contain an item with linkId='" + + BpmnUserTask.Codes.BUSINESS_KEY + "'")); + + questionnaireResponse.getItem().stream().filter(i -> BpmnUserTask.Codes.USER_TASK_ID.equals(i.getLinkId())) + .findFirst() + .orElseThrow(() -> new RuntimeException("QuestionnaireResponse does not contain an item with linkId='" + + BpmnUserTask.Codes.USER_TASK_ID + "'")); + + if (!QuestionnaireResponse.QuestionnaireResponseStatus.INPROGRESS.equals(questionnaireResponse.getStatus())) + throw new RuntimeException("QuestionnaireResponse must be in status 'in-progress'"); + } + + /** + * Override this method to modify the {@link QuestionnaireResponse} before it will be created in state + * {@link QuestionnaireResponse.QuestionnaireResponseStatus#INPROGRESS} on the DSF FHIR server + * + * @param userTask + * not null, user task on which this {@link QuestionnaireResponse} is based + * @param beforeCreate + * not null, containing an answer placeholder for every item in the corresponding + * {@link Questionnaire} + */ + protected void beforeQuestionnaireResponseCreate(DelegateTask userTask, QuestionnaireResponse beforeCreate) + { + // Nothing to do in default behavior + } + + /** + * Override this method to execute code after the {@link QuestionnaireResponse} resource has been created on the + * DSF FHIR server + * + * @param userTask + * not null, user task on which this {@link QuestionnaireResponse} is based + * @param afterCreate + * not null, created on the DSF FHIR server + */ + protected void afterQuestionnaireResponseCreate(DelegateTask userTask, QuestionnaireResponse afterCreate) + { + // Nothing to do in default behavior + } + + private void updateFailedIfInprogress(List tasks, String errorMessage) + { + for (int i = tasks.size() - 1; i >= 0; i--) + { + Task task = tasks.get(i); + + if (TaskStatus.INPROGRESS.equals(task.getStatus())) + { + task.setStatus(Task.TaskStatus.FAILED); + task.addOutput(new TaskOutputComponent(new CodeableConcept(BpmnMessage.error()), + new StringType(errorMessage))); + updateAndHandleException(task); + } + else + { + logger.debug("Not updating Task {} with status: {}", + api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), task.getStatus()); + } + } + } + + private void updateAndHandleException(Task task) + { + try + { + logger.debug("Updating Task {}, new status: {}", api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), + task.getStatus().toCode()); + + api.getFhirWebserviceClientProvider().getLocalWebserviceClient().withMinimalReturn().update(task); + } + catch (Exception e) + { + logger.debug("Unable to update Task {}", api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), e); + logger.error("Unable to update Task {}: {} - {}", api.getTaskHelper().getLocalVersionlessAbsoluteUrl(task), + e.getClass().getName(), e.getMessage()); + } + } +} diff --git a/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/variables/Variables.java b/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/variables/Variables.java new file mode 100644 index 000000000..f0083d4e3 --- /dev/null +++ b/dsf-bpe/dsf-bpe-process-api-v1-operaton/src/main/java/dev/dsf/bpe/v1/variables/Variables.java @@ -0,0 +1,620 @@ +/* + * Copyright 2018-2025 Heilbronn University of Applied Sciences + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * 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. + */ +package dev.dsf.bpe.v1.variables; + +import java.io.File; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.hl7.fhir.r4.model.QuestionnaireResponse; +import org.hl7.fhir.r4.model.Resource; +import org.hl7.fhir.r4.model.Task; +import org.operaton.bpm.engine.variable.value.TypedValue; + +import dev.dsf.bpe.v1.constants.BpmnExecutionVariables; + +/** + * Gives access to process execution variables. Includes factory methods for {@link Target} and {@link Targets} values. + */ +public interface Variables +{ + /** + * Sets execution variable {@link BpmnExecutionVariables#ALTERNATIVE_BUSINESS_KEY} + * + * @param alternativeBusinessKey + * may be null + */ + void setAlternativeBusinessKey(String alternativeBusinessKey); + + /** + * Creates a new {@link Target} object. + *

+ * A not null correlationKey should be used if return messages aka. Task resources + * from multiple organizations with the same message-name are expected in a following multi instance message receive + * task or intermediate message catch event in a multi instance subprocess.
+ * Note: The correlationKey needs to be set as a {@link BpmnExecutionVariables#CORRELATION_KEY} variable in the + * message receive task or intermediate message catch event of a subprocess before incoming messages aka. Task + * resources can be correlated. Within a BPMN file this can be accomplished by setting an input variable with name: + * {@link BpmnExecutionVariables#CORRELATION_KEY}, type:
string or expression, and value: + * ${target.correlationKey}. + *

+ * A not null correlationKey should also be used when sending a message aka. Task + * resource back to an organization waiting for multiple returns. + * + * @param organizationIdentifierValue + * not null + * @param endpointIdentifierValue + * not null + * @param endpointAddress + * not null + * @param correlationKey + * not null if used for sending multiple messages and multiple messages with the same + * message-name are expected in return + * @return new {@link Target} object + * @see #createTarget(String, String, String) + * @see #setTarget(Target) + */ + Target createTarget(String organizationIdentifierValue, String endpointIdentifierValue, String endpointAddress, + String correlationKey); + + /** + * Creates a new {@link Target} object. + * + * See {@link #createTarget(String, String, String, String)} for sending a correlation-key for 1:n or n:1 + * relationships. + * + * @param organizationIdentifierValue + * not null + * @param endpointIdentifierValue + * not null + * @param endpointAddress + * not null + * @return new {@link Target} object + * @see #createTarget(String, String, String, String) + * @see #setTarget(Target) + */ + default Target createTarget(String organizationIdentifierValue, String endpointIdentifierValue, + String endpointAddress) + { + return createTarget(organizationIdentifierValue, endpointIdentifierValue, endpointAddress, null); + } + + /** + * Sets execution variable {@link BpmnExecutionVariables#TARGET} + * + * @param target + * may be null + * @throws IllegalArgumentException + * if the given target object is not supported, meaning the object was not created by this + * {@link Variables} implementation + * @see #createTarget(String, String, String) + * @see #createTarget(String, String, String, String) + * @see #getTarget() + */ + void setTarget(Target target) throws IllegalArgumentException; + + /** + * Retrieves execution variable {@link BpmnExecutionVariables#TARGET} + * + * @return Execution variable {@link BpmnExecutionVariables#TARGET}, may be null + */ + Target getTarget(); + + /** + * Creates a new target list. + * + * Use ${targets.entries} as a multi instance collection and target as + * the element variable to loop over this list in a multi instance task or subprocess. + * + * @param targets + * {@link Target} objects to incorporate into the created list + * @return a new target list + * @throws IllegalArgumentException + * if one of the given target objects is not supported, meaning the object was not created by + * this {@link Variables} implementation + * @see #createTarget(String, String, String) + * @see #createTarget(String, String, String, String) + * @see #setTargets(Targets) + */ + default Targets createTargets(Target... targets) + { + return createTargets(Arrays.asList(targets)); + } + + /** + * Creates a new target list. + * + * Use ${targets.entries} as a multi instance collection and target as + * the element variable to loop over this list in a multi instance task or subprocess. + * + * @param targets + * {@link Target} objects to incorporate into the created list, may be null + * @return a new target list + * @throws IllegalArgumentException + * if one of the given target objects is not supported, meaning the object was not created by + * this {@link Variables} implementation + * @see #createTarget(String, String, String) + * @see #createTarget(String, String, String, String) + * @see #setTargets(Targets) + */ + Targets createTargets(List targets); + + /** + * Sets execution variable {@link BpmnExecutionVariables#TARGETS}. + * + * Use ${targets.entries} as a multi instance collection and + * + * @param targets + * may be null + * @see #createTargets(List) + * @see #createTargets(Target...) + * @see #getTargets() + */ + void setTargets(Targets targets); + + /** + * Retrieves execution variable {@link BpmnExecutionVariables#TARGETS} + * + * @return Execution variable {@link BpmnExecutionVariables#TARGETS}, may be null + * @see #setTargets(Targets) + */ + Targets getTargets(); + + /** + * Sets execution variable with the given variableName to the given FHIR {@link Resource} list + * + * @param variableName + * not null + * @param resources + */ + void setResourceList(String variableName, List resources); + + /** + * Retrieves FHIR {@link Resource} list execution variable with the given variableName + * + * @param + * FHIR resource type + * @param variableName + * not null + * @return list of FHIR resources from execution variables for the given variableName, may be + * null + */ + List getResourceList(String variableName); + + /** + * Sets execution variable with the given variableName to the given FHIR {@link Resource} + * + * @param variableName + * not null + * @param resource + * may be null + */ + void setResource(String variableName, Resource resource); + + /** + * Retrieves FHIR {@link Resource} execution variable with the given variableName + * + * @param + * FHIR resource type + * @param variableName + * not null + * @return value from execution variables for the given variableName, may be null + */ + R getResource(String variableName); + + /** + * Returns the {@link Task} associated with the message start event of the process. + * + * @return {@link Task} that started the process instance, not null + * @see #updateTask(Task) + * @see #getLatestTask() + * @see #getTasks() + */ + Task getStartTask(); + + /** + * Returns the latest {@link Task} received by this process or subprocess via a intermediate message catch event or + * message receive task. + * + * @return Last received {@link Task} of the current process or subprocess, not null + * @see #updateTask(Task) + * @see #getStartTask() + * @see #getCurrentTasks() + */ + Task getLatestTask(); + + /** + * @return All {@link Task} resources received + * @see #getCurrentTasks() + */ + List getTasks(); + + /** + * @return All {@link Task} resources received by the current process or subprocess + * @see #getTasks() + */ + List getCurrentTasks(); + + /** + * Does nothing if the given task is null. Forces an update to the Task list variable used + * internally to track all received Task resources if the given task object is already part of this list. + * + * @param task + * may be null + * @see #getStartTask() + * @see #getLatestTask() + * @see #getTasks() + * @see #getCurrentTasks() + */ + void updateTask(Task task); + + /** + * @return Last received {@link QuestionnaireResponse}, null if nothing received yet + */ + QuestionnaireResponse getLatestReceivedQuestionnaireResponse(); + + /** + * Sets execution variable with the given variableName to the given {@link TypedValue} + * + * @param variableName + * not null + * @param value + * may be null + * @see #getVariable(String) + * @see #setInteger(String, Integer) + * @see #setString(String, String) + * @see #setBoolean(String, Boolean) + * @see #setByteArray(String, byte[]) + * @see #setDate(String, Date) + * @see #setLong(String, Long) + * @see #setShort(String, Short) + * @see #setDouble(String, Double) + * @see #setNumber(String, Number) + * @see #setFile(String, File) + */ + void setVariable(String variableName, TypedValue value); + + /** + * Retrieves execution variable with the given variableName + * + * @param variableName + * not null + * @return value from execution variables for the given variableName, may be null + * @see #setVariable(String, TypedValue) + * @see #getInteger(String) + * @see #getString(String) + * @see #getBoolean(String) + * @see #getByteArray(String) + * @see #getDate(String) + * @see #getLong(String) + * @see #getShort(String) + * @see #getDouble(String) + * @see #getNumber(String) + * @see #getFile(String) + */ + Object getVariable(String variableName); + + /** + * Sets execution variable with the given variableName to the given {@link Integer} + * + * @param variableName + * not null + * @param value + * may be null + * @see #getInteger(String) + * @see #setVariable(String, TypedValue) + */ + default void setInteger(String variableName, Integer value) + { + setVariable(variableName, org.operaton.bpm.engine.variable.Variables.integerValue(value)); + } + + /** + * Retrieves {@link Integer} execution variable with the given variableName + * + * @param variableName + * not null + * @return value from execution variables for the given variableName, may be null + * @throws ClassCastException + * if the stored value is not a {@link Integer} + * @see #setInteger(String, Integer) + * @see #getVariable(String) + */ + default Integer getInteger(String variableName) + { + return (Integer) getVariable(variableName); + } + + /** + * Sets execution variable with the given variableName to the given {@link String} + * + * @param variableName + * not null + * @param value + * may be null + * @see #getString(String) + * @see #setVariable(String, TypedValue) + */ + default void setString(String variableName, String value) + { + setVariable(variableName, org.operaton.bpm.engine.variable.Variables.stringValue(value)); + } + + /** + * Retrieves {@link String} execution variable with the given variableName + * + * @param variableName + * not null + * @return value from execution variables for the given variableName, may be null + * @throws ClassCastException + * if the stored value is not a {@link String} + * @see #setString(String, String) + * @see #getVariable(String) + */ + default String getString(String variableName) + { + return (String) getVariable(variableName); + } + + /** + * Sets execution variable with the given variableName to the given {@link Boolean} + * + * @param variableName + * not null + * @param value + * may be null + * @see #getBoolean(String) + * @see #setVariable(String, TypedValue) + */ + default void setBoolean(String variableName, Boolean value) + { + setVariable(variableName, org.operaton.bpm.engine.variable.Variables.booleanValue(value)); + } + + /** + * Retrieves {@link Boolean} execution variable with the given variableName + * + * @param variableName + * not null + * @return value from execution variables for the given variableName, may be null + * @throws ClassCastException + * if the stored value is not a {@link Boolean} + * @see #setBoolean(String, Boolean) + * @see #getVariable(String) + */ + default Boolean getBoolean(String variableName) + { + return (Boolean) getVariable(variableName); + } + + /** + * Sets execution variable with the given variableName to the given byte[] + * + * @param variableName + * not null + * @param value + * may be null + * @see #getByteArray(String) + * @see #setVariable(String, TypedValue) + */ + default void setByteArray(String variableName, byte[] value) + { + setVariable(variableName, org.operaton.bpm.engine.variable.Variables.byteArrayValue(value)); + } + + /** + * Retrieves byte[] execution variable with the given variableName + * + * @param variableName + * not null + * @return value from execution variables for the given variableName, may be null + * @throws ClassCastException + * if the stored value is not a byte[] + * @see #setByteArray(String, byte[]) + * @see #getVariable(String) + */ + default byte[] getByteArray(String variableName) + { + return (byte[]) getVariable(variableName); + } + + /** + * Sets execution variable with the given variableName to the given {@link Date} + * + * @param variableName + * not null + * @param value + * may be null + * @see #getDate(String) + * @see #setVariable(String, TypedValue) + */ + default void setDate(String variableName, Date value) + { + setVariable(variableName, org.operaton.bpm.engine.variable.Variables.dateValue(value)); + } + + /** + * Retrieves {@link Date} execution variable with the given variableName + * + * @param variableName + * not null + * @return value from execution variables for the given variableName, may be null + * @throws ClassCastException + * if the stored value is not a {@link Date} + * @see #setDate(String, Date) + * @see #getVariable(String) + */ + default Date getDate(String variableName) + { + return (Date) getVariable(variableName); + } + + /** + * Sets execution variable with the given variableName to the given {@link Long} + * + * @param variableName + * not null + * @param value + * may be null + * @see #getLong(String) + * @see #setVariable(String, TypedValue) + */ + default void setLong(String variableName, Long value) + { + setVariable(variableName, org.operaton.bpm.engine.variable.Variables.longValue(value)); + } + + /** + * Retrieves {@link Long} execution variable with the given variableName + * + * @param variableName + * not null + * @return value from execution variables for the given variableName, may be null + * @throws ClassCastException + * if the stored value is not a {@link Long} + * @see #setLong(String, Long) + * @see #getVariable(String) + */ + default Long getLong(String variableName) + { + return (Long) getVariable(variableName); + } + + /** + * Sets execution variable with the given variableName to the given {@link Short} + * + * @param variableName + * not null + * @param value + * may be null + * @see #getShort(String) + * @see #setVariable(String, TypedValue) + */ + default void setShort(String variableName, Short value) + { + setVariable(variableName, org.operaton.bpm.engine.variable.Variables.shortValue(value)); + } + + /** + * Retrieves {@link Short} execution variable with the given variableName + * + * @param variableName + * not null + * @return value from execution variables for the given variableName, may be null + * @throws ClassCastException + * if the stored value is not a {@link Short} + * @see #setShort(String, Short) + * @see #getVariable(String) + */ + default Short getShort(String variableName) + { + return (Short) getVariable(variableName); + } + + /** + * Sets execution variable with the given variableName to the given {@link Double} + * + * @param variableName + * not null + * @param value + * may be null + * @see #getDouble(String) + * @see #setVariable(String, TypedValue) + */ + default void setDouble(String variableName, Double value) + { + setVariable(variableName, org.operaton.bpm.engine.variable.Variables.doubleValue(value)); + } + + /** + * Retrieves {@link Double} execution variable with the given variableName + * + * @param variableName + * not null + * @return value from execution variables for the given variableName, may be null + * @throws ClassCastException + * if the stored value is not a {@link Double} + * @see #setDouble(String, Double) + * @see #getVariable(String) + */ + default Double getDouble(String variableName) + { + return (Double) getVariable(variableName); + } + + /** + * Sets execution variable with the given variableName to the given {@link Number} + * + * @param variableName + * not null + * @param value + * may be null + * @see #getNumber(String) + * @see #setVariable(String, TypedValue) + */ + default void setNumber(String variableName, Number value) + { + setVariable(variableName, org.operaton.bpm.engine.variable.Variables.numberValue(value)); + } + + /** + * Retrieves {@link Number} execution variable with the given variableName + * + * @param variableName + * not null + * @return value from execution variables for the given variableName, may be null + * @throws ClassCastException + * if the stored value is not a {@link Number} + * @see #setNumber(String, Number) + * @see #getVariable(String) + */ + default Number getNumber(String variableName) + { + return (Number) getVariable(variableName); + } + + /** + * Sets execution variable with the given variableName to the given {@link File} + * + * @param variableName + * not null + * @param value + * may be null + * @see #getFile(String) + * @see #setVariable(String, TypedValue) + */ + default void setFile(String variableName, File value) + { + setVariable(variableName, org.operaton.bpm.engine.variable.Variables.fileValue(value)); + } + + /** + * Retrieves {@link File} execution variable with the given variableName + * + * @param variableName + * not null + * @return value from execution variables for the given variableName, may be null + * @throws ClassCastException + * if the stored value is not a {@link File} + * @see #setFile(String, File) + * @see #getVariable(String) + */ + default File getFile(String variableName) + { + return (File) getVariable(variableName); + } +} diff --git a/dsf-bpe/dsf-bpe-process-api-v1/pom.xml b/dsf-bpe/dsf-bpe-process-api-v1/pom.xml index 3d9db2ee4..28b3ed222 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1/pom.xml +++ b/dsf-bpe/dsf-bpe-process-api-v1/pom.xml @@ -33,14 +33,19 @@ DSF BPE Process API v1 + + dev.dsf + dsf-bpe-process-api-v1-base + ca.uhn.hapi.fhir hapi-fhir-structures-r4 ${hapi.fhir.version.v1} - org.operaton.bpm - operaton-engine + org.camunda.bpm + camunda-engine + 7.24.0 org.springframework @@ -84,4 +89,36 @@ + + + + + org.apache.maven.plugins + maven-shade-plugin + + + package + + shade + + + + + dev.dsf:dsf-bpe-process-api-v1-base + + + true + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + src/main/java;../dsf-bpe-process-api-v1-base/src/main/java + + + + \ No newline at end of file diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/ProcessPluginApi.java b/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/ProcessPluginApi.java index ff1df272e..e90bba132 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/ProcessPluginApi.java +++ b/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/ProcessPluginApi.java @@ -15,7 +15,7 @@ */ package dev.dsf.bpe.v1; -import org.operaton.bpm.engine.delegate.DelegateExecution; +import org.camunda.bpm.engine.delegate.DelegateExecution; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/activity/AbstractServiceDelegate.java b/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/activity/AbstractServiceDelegate.java index 14945f276..125d8c95c 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/activity/AbstractServiceDelegate.java +++ b/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/activity/AbstractServiceDelegate.java @@ -18,14 +18,14 @@ import java.util.List; import java.util.Objects; +import org.camunda.bpm.engine.delegate.BpmnError; +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.camunda.bpm.engine.delegate.JavaDelegate; import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.Task; import org.hl7.fhir.r4.model.Task.TaskOutputComponent; import org.hl7.fhir.r4.model.Task.TaskStatus; -import org.operaton.bpm.engine.delegate.BpmnError; -import org.operaton.bpm.engine.delegate.DelegateExecution; -import org.operaton.bpm.engine.delegate.JavaDelegate; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/activity/AbstractTaskMessageSend.java b/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/activity/AbstractTaskMessageSend.java index ef3862e41..8d20b3dbf 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/activity/AbstractTaskMessageSend.java +++ b/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/activity/AbstractTaskMessageSend.java @@ -21,6 +21,12 @@ import java.util.UUID; import java.util.stream.Stream; +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.camunda.bpm.engine.delegate.JavaDelegate; +import org.camunda.bpm.engine.impl.el.FixedValue; +import org.camunda.bpm.model.bpmn.instance.EndEvent; +import org.camunda.bpm.model.bpmn.instance.IntermediateThrowEvent; +import org.camunda.bpm.model.bpmn.instance.SendTask; import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Meta; @@ -32,12 +38,6 @@ import org.hl7.fhir.r4.model.Task.TaskIntent; import org.hl7.fhir.r4.model.Task.TaskOutputComponent; import org.hl7.fhir.r4.model.Task.TaskStatus; -import org.operaton.bpm.engine.delegate.DelegateExecution; -import org.operaton.bpm.engine.delegate.JavaDelegate; -import org.operaton.bpm.engine.impl.el.FixedValue; -import org.operaton.bpm.model.bpmn.instance.EndEvent; -import org.operaton.bpm.model.bpmn.instance.IntermediateThrowEvent; -import org.operaton.bpm.model.bpmn.instance.SendTask; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/activity/DefaultUserTaskListener.java b/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/activity/DefaultUserTaskListener.java index 04b9c7e49..738e29b97 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/activity/DefaultUserTaskListener.java +++ b/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/activity/DefaultUserTaskListener.java @@ -21,6 +21,9 @@ import java.util.Objects; import java.util.stream.Collectors; +import org.camunda.bpm.engine.delegate.DelegateExecution; +import org.camunda.bpm.engine.delegate.DelegateTask; +import org.camunda.bpm.engine.delegate.TaskListener; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.Questionnaire; @@ -32,9 +35,6 @@ import org.hl7.fhir.r4.model.Task.TaskOutputComponent; import org.hl7.fhir.r4.model.Task.TaskStatus; import org.hl7.fhir.r4.model.Type; -import org.operaton.bpm.engine.delegate.DelegateExecution; -import org.operaton.bpm.engine.delegate.DelegateTask; -import org.operaton.bpm.engine.delegate.TaskListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; @@ -87,7 +87,7 @@ public final void notify(DelegateTask userTask) { logger.trace("Execution of user task with id='{}'", execution.getCurrentActivityId()); - String questionnaireUrlWithVersion = userTask.getBpmnModelElementInstance().getOperatonFormKey(); + String questionnaireUrlWithVersion = userTask.getBpmnModelElementInstance().getCamundaFormKey(); Questionnaire questionnaire = readQuestionnaire(questionnaireUrlWithVersion); String businessKey = execution.getBusinessKey(); diff --git a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/variables/Variables.java b/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/variables/Variables.java index f0083d4e3..ba0e89249 100644 --- a/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/variables/Variables.java +++ b/dsf-bpe/dsf-bpe-process-api-v1/src/main/java/dev/dsf/bpe/v1/variables/Variables.java @@ -20,10 +20,10 @@ import java.util.Date; import java.util.List; +import org.camunda.bpm.engine.variable.value.TypedValue; import org.hl7.fhir.r4.model.QuestionnaireResponse; import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.Task; -import org.operaton.bpm.engine.variable.value.TypedValue; import dev.dsf.bpe.v1.constants.BpmnExecutionVariables; @@ -320,7 +320,7 @@ default Targets createTargets(Target... targets) */ default void setInteger(String variableName, Integer value) { - setVariable(variableName, org.operaton.bpm.engine.variable.Variables.integerValue(value)); + setVariable(variableName, org.camunda.bpm.engine.variable.Variables.integerValue(value)); } /** @@ -351,7 +351,7 @@ default Integer getInteger(String variableName) */ default void setString(String variableName, String value) { - setVariable(variableName, org.operaton.bpm.engine.variable.Variables.stringValue(value)); + setVariable(variableName, org.camunda.bpm.engine.variable.Variables.stringValue(value)); } /** @@ -382,7 +382,7 @@ default String getString(String variableName) */ default void setBoolean(String variableName, Boolean value) { - setVariable(variableName, org.operaton.bpm.engine.variable.Variables.booleanValue(value)); + setVariable(variableName, org.camunda.bpm.engine.variable.Variables.booleanValue(value)); } /** @@ -413,7 +413,7 @@ default Boolean getBoolean(String variableName) */ default void setByteArray(String variableName, byte[] value) { - setVariable(variableName, org.operaton.bpm.engine.variable.Variables.byteArrayValue(value)); + setVariable(variableName, org.camunda.bpm.engine.variable.Variables.byteArrayValue(value)); } /** @@ -444,7 +444,7 @@ default byte[] getByteArray(String variableName) */ default void setDate(String variableName, Date value) { - setVariable(variableName, org.operaton.bpm.engine.variable.Variables.dateValue(value)); + setVariable(variableName, org.camunda.bpm.engine.variable.Variables.dateValue(value)); } /** @@ -475,7 +475,7 @@ default Date getDate(String variableName) */ default void setLong(String variableName, Long value) { - setVariable(variableName, org.operaton.bpm.engine.variable.Variables.longValue(value)); + setVariable(variableName, org.camunda.bpm.engine.variable.Variables.longValue(value)); } /** @@ -506,7 +506,7 @@ default Long getLong(String variableName) */ default void setShort(String variableName, Short value) { - setVariable(variableName, org.operaton.bpm.engine.variable.Variables.shortValue(value)); + setVariable(variableName, org.camunda.bpm.engine.variable.Variables.shortValue(value)); } /** @@ -537,7 +537,7 @@ default Short getShort(String variableName) */ default void setDouble(String variableName, Double value) { - setVariable(variableName, org.operaton.bpm.engine.variable.Variables.doubleValue(value)); + setVariable(variableName, org.camunda.bpm.engine.variable.Variables.doubleValue(value)); } /** @@ -568,7 +568,7 @@ default Double getDouble(String variableName) */ default void setNumber(String variableName, Number value) { - setVariable(variableName, org.operaton.bpm.engine.variable.Variables.numberValue(value)); + setVariable(variableName, org.camunda.bpm.engine.variable.Variables.numberValue(value)); } /** @@ -599,7 +599,7 @@ default Number getNumber(String variableName) */ default void setFile(String variableName, File value) { - setVariable(variableName, org.operaton.bpm.engine.variable.Variables.fileValue(value)); + setVariable(variableName, org.camunda.bpm.engine.variable.Variables.fileValue(value)); } /** diff --git a/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/ReadAccessHelperImpl.java b/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/ReadAccessHelperImpl.java index 8efcf149e..a7061a045 100644 --- a/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/ReadAccessHelperImpl.java +++ b/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/ReadAccessHelperImpl.java @@ -31,28 +31,18 @@ import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; +import dev.dsf.bpe.v2.constants.CodeSystems; +import dev.dsf.bpe.v2.constants.NamingSystems; + public class ReadAccessHelperImpl implements ReadAccessHelper { - private static final String READ_ACCESS_TAG_SYSTEM = "http://dsf.dev/fhir/CodeSystem/read-access-tag"; - private static final String READ_ACCESS_TAG_VALUE_LOCAL = "LOCAL"; - private static final String READ_ACCESS_TAG_VALUE_ORGANIZATION = "ORGANIZATION"; - private static final String READ_ACCESS_TAG_VALUE_ROLE = "ROLE"; - private static final String READ_ACCESS_TAG_VALUE_ALL = "ALL"; - - private static final String ORGANIZATION_IDENTIFIER_SYSTEM = "http://dsf.dev/sid/organization-identifier"; - - private static final String EXTENSION_READ_ACCESS_ORGANIZATION = "http://dsf.dev/fhir/StructureDefinition/extension-read-access-organization"; - - private static final String EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE = "http://dsf.dev/fhir/StructureDefinition/extension-read-access-parent-organization-role"; - private static final String EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION = "parent-organization"; - private static final String EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE = "organization-role"; - - private static final List READ_ACCESS_TAG_VALUES = List.of(READ_ACCESS_TAG_VALUE_LOCAL, - READ_ACCESS_TAG_VALUE_ORGANIZATION, READ_ACCESS_TAG_VALUE_ROLE, READ_ACCESS_TAG_VALUE_ALL); + private static final List READ_ACCESS_TAG_VALUES = List.of(CodeSystems.ReadAccessTag.Codes.LOCAL, + CodeSystems.ReadAccessTag.Codes.ORGANIZATION, CodeSystems.ReadAccessTag.Codes.ROLE, + CodeSystems.ReadAccessTag.Codes.ALL); private Predicate matchesTagValue(String value) { - return c -> c != null && READ_ACCESS_TAG_SYSTEM.equals(c.getSystem()) && c.hasCode() + return c -> c != null && CodeSystems.ReadAccessTag.SYSTEM.equals(c.getSystem()) && c.hasCode() && c.getCode().equals(value); } @@ -62,8 +52,8 @@ public R addLocal(R resource) if (resource == null) return null; - resource.getMeta().getTag().removeIf(matchesTagValue(READ_ACCESS_TAG_VALUE_ALL)); - resource.getMeta().addTag().setSystem(READ_ACCESS_TAG_SYSTEM).setCode(READ_ACCESS_TAG_VALUE_LOCAL); + resource.getMeta().getTag().removeIf(matchesTagValue(CodeSystems.ReadAccessTag.Codes.ALL)); + resource.getMeta().addTag(CodeSystems.ReadAccessTag.local()); return resource; } @@ -76,12 +66,13 @@ public R addOrganization(R resource, String organizationIde Objects.requireNonNull(organizationIdentifier, "organizationIdentifier"); - if (resource.getMeta().getTag().stream().noneMatch(matchesTagValue(READ_ACCESS_TAG_VALUE_LOCAL))) + if (resource.getMeta().getTag().stream().noneMatch(matchesTagValue(CodeSystems.ReadAccessTag.Codes.LOCAL))) addLocal(resource); - resource.getMeta().addTag().setSystem(READ_ACCESS_TAG_SYSTEM).setCode(READ_ACCESS_TAG_VALUE_ORGANIZATION) - .addExtension().setUrl(EXTENSION_READ_ACCESS_ORGANIZATION) - .setValue(new Identifier().setSystem(ORGANIZATION_IDENTIFIER_SYSTEM).setValue(organizationIdentifier)); + resource.getMeta().addTag().setSystem(CodeSystems.ReadAccessTag.SYSTEM) + .setCode(CodeSystems.ReadAccessTag.Codes.ORGANIZATION).addExtension() + .setUrl(EXTENSION_READ_ACCESS_ORGANIZATION) + .setValue(NamingSystems.OrganizationIdentifier.withValue(organizationIdentifier)); return resource; } @@ -97,12 +88,13 @@ public R addOrganization(R resource, Organization organizat if (!organization.hasIdentifier()) throw new IllegalArgumentException("organization has no identifier"); - Optional identifierValue = organization.getIdentifier().stream().filter(Identifier::hasSystem) - .filter(i -> ORGANIZATION_IDENTIFIER_SYSTEM.equals(i.getSystem())).filter(Identifier::hasValue) - .map(Identifier::getValue).filter(v -> !v.isBlank()).findFirst(); + Optional identifierValue = NamingSystems.OrganizationIdentifier.findFirst(organization) + .map(Identifier::getValue).filter(v -> !v.isBlank()); - return addOrganization(resource, identifierValue.orElseThrow(() -> new IllegalArgumentException( - "organization has no non blank identifier value with system " + ORGANIZATION_IDENTIFIER_SYSTEM))); + return addOrganization(resource, + identifierValue.orElseThrow( + () -> new IllegalArgumentException("organization has no non blank identifier value with system " + + NamingSystems.OrganizationIdentifier.SID))); } @Override @@ -116,13 +108,14 @@ public R addRole(R resource, String parentOrganizationIdent Objects.requireNonNull(roleSystem, "roleSystem"); Objects.requireNonNull(roleCode, "roleCode"); - if (resource.getMeta().getTag().stream().noneMatch(matchesTagValue(READ_ACCESS_TAG_VALUE_LOCAL))) + if (resource.getMeta().getTag().stream().noneMatch(matchesTagValue(CodeSystems.ReadAccessTag.Codes.LOCAL))) addLocal(resource); - Extension ex = resource.getMeta().addTag().setSystem(READ_ACCESS_TAG_SYSTEM).setCode(READ_ACCESS_TAG_VALUE_ROLE) - .addExtension().setUrl(EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE); - ex.addExtension().setUrl(EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION).setValue( - new Identifier().setSystem(ORGANIZATION_IDENTIFIER_SYSTEM).setValue(parentOrganizationIdentifier)); + Extension ex = resource.getMeta().addTag().setSystem(CodeSystems.ReadAccessTag.SYSTEM) + .setCode(CodeSystems.ReadAccessTag.Codes.ROLE).addExtension() + .setUrl(EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE); + ex.addExtension().setUrl(EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION) + .setValue(NamingSystems.OrganizationIdentifier.withValue(parentOrganizationIdentifier)); ex.addExtension().setUrl(EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE) .setValue(new Coding().setSystem(roleSystem).setCode(roleCode)); return resource; @@ -139,11 +132,11 @@ public R addRole(R resource, OrganizationAffiliation affili throw new IllegalArgumentException("affiliation has no parent-organization reference"); if (!affiliation.getOrganization().hasIdentifier()) throw new IllegalArgumentException("affiliation has no parent-organization reference with identifier"); - if (!affiliation.getOrganization().getIdentifier().hasSystem() - || !ORGANIZATION_IDENTIFIER_SYSTEM.equals(affiliation.getOrganization().getIdentifier().getSystem())) + if (!affiliation.getOrganization().getIdentifier().hasSystem() || !NamingSystems.OrganizationIdentifier.SID + .equals(affiliation.getOrganization().getIdentifier().getSystem())) throw new IllegalArgumentException( "affiliation has no parent-organization reference with identifier system " - + ORGANIZATION_IDENTIFIER_SYSTEM); + + NamingSystems.OrganizationIdentifier.SID); if (!affiliation.getOrganization().getIdentifier().hasValue() || affiliation.getOrganization().getIdentifier().getValue().isBlank()) throw new IllegalArgumentException( @@ -170,11 +163,12 @@ public R addAll(R resource) return null; resource.getMeta().getTag() - .removeIf(matchesTagValue(READ_ACCESS_TAG_VALUE_LOCAL) - .or(matchesTagValue(READ_ACCESS_TAG_VALUE_ORGANIZATION)) - .or(matchesTagValue(READ_ACCESS_TAG_VALUE_ROLE))); + .removeIf(matchesTagValue(CodeSystems.ReadAccessTag.Codes.LOCAL) + .or(matchesTagValue(CodeSystems.ReadAccessTag.Codes.ORGANIZATION)) + .or(matchesTagValue(CodeSystems.ReadAccessTag.Codes.ROLE))); + + resource.getMeta().addTag(CodeSystems.ReadAccessTag.all()); - resource.getMeta().addTag().setSystem(READ_ACCESS_TAG_SYSTEM).setCode(READ_ACCESS_TAG_VALUE_ALL); return resource; } @@ -184,7 +178,8 @@ public boolean hasLocal(Resource resource) if (resource == null || !resource.hasMeta() || !resource.getMeta().hasTag()) return false; - return resource.getMeta().getTag(READ_ACCESS_TAG_SYSTEM, READ_ACCESS_TAG_VALUE_LOCAL) != null; + return resource.getMeta().getTag(CodeSystems.ReadAccessTag.SYSTEM, + CodeSystems.ReadAccessTag.Codes.LOCAL) != null; } @Override @@ -193,8 +188,8 @@ public boolean hasOrganization(Resource resource, String organizationIdentifier) if (resource == null || !resource.hasMeta() || !resource.getMeta().hasTag()) return false; - Stream extensions = getTagExtensions(resource, READ_ACCESS_TAG_SYSTEM, - READ_ACCESS_TAG_VALUE_ORGANIZATION, EXTENSION_READ_ACCESS_ORGANIZATION); + Stream extensions = getTagExtensions(resource, CodeSystems.ReadAccessTag.SYSTEM, + CodeSystems.ReadAccessTag.Codes.ORGANIZATION, EXTENSION_READ_ACCESS_ORGANIZATION); return extensions.filter(Extension::hasValue).map(Extension::getValue).filter(v -> v instanceof Identifier) .map(v -> (Identifier) v).filter(Identifier::hasValue) @@ -208,8 +203,9 @@ public boolean hasOrganization(Resource resource, Organization organization) return false; return organization.hasIdentifier() && organization.getIdentifier().stream().filter(Identifier::hasSystem) - .filter(i -> ORGANIZATION_IDENTIFIER_SYSTEM.equals(i.getSystem())).filter(Identifier::hasValue) - .map(Identifier::getValue).anyMatch(identifier -> hasOrganization(resource, identifier)); + .filter(i -> NamingSystems.OrganizationIdentifier.SID.equals(i.getSystem())) + .filter(Identifier::hasValue).map(Identifier::getValue) + .anyMatch(identifier -> hasOrganization(resource, identifier)); } private Stream getTagExtensions(Resource resource, String tagSystem, String tagCode, String extensionUrl) @@ -225,7 +221,8 @@ public boolean hasAnyOrganization(Resource resource) if (resource == null || !resource.hasMeta() || !resource.getMeta().hasTag()) return false; - return resource.getMeta().getTag(READ_ACCESS_TAG_SYSTEM, READ_ACCESS_TAG_VALUE_ORGANIZATION) != null; + return resource.getMeta().getTag(CodeSystems.ReadAccessTag.SYSTEM, + CodeSystems.ReadAccessTag.Codes.ORGANIZATION) != null; } @Override @@ -234,8 +231,8 @@ public boolean hasRole(Resource resource, String parentOrganizationIdentifier, S if (resource == null || !resource.hasMeta() || !resource.getMeta().hasTag()) return false; - Stream extensions = getTagExtensions(resource, READ_ACCESS_TAG_SYSTEM, READ_ACCESS_TAG_VALUE_ROLE, - EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE); + Stream extensions = getTagExtensions(resource, CodeSystems.ReadAccessTag.SYSTEM, + CodeSystems.ReadAccessTag.Codes.ROLE, EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE); return extensions.filter(Extension::hasExtension) .anyMatch(matches(parentOrganizationIdentifier, roleSystem, roleCode)); @@ -260,7 +257,7 @@ private Predicate matches(String parentOrganizationIdentifier EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION)) .filter(Extension::hasValue).map(Extension::getValue).filter(v -> v instanceof Identifier) .map(v -> (Identifier) v).filter(Identifier::hasSystem).filter(Identifier::hasValue) - .anyMatch(i -> ORGANIZATION_IDENTIFIER_SYSTEM.equals(i.getSystem()) + .anyMatch(i -> NamingSystems.OrganizationIdentifier.SID.equals(i.getSystem()) && Objects.equals(i.getValue(), parentOrganizationIdentifier)); boolean role = extensions.getExtension().stream().filter(Extension::hasUrl) .filter(e -> Objects.equals(e.getUrl(), @@ -298,7 +295,8 @@ public boolean hasAnyRole(Resource resource) if (resource == null || !resource.hasMeta() || !resource.getMeta().hasTag()) return false; - return resource.getMeta().getTag(READ_ACCESS_TAG_SYSTEM, READ_ACCESS_TAG_VALUE_ROLE) != null; + return resource.getMeta().getTag(CodeSystems.ReadAccessTag.SYSTEM, + CodeSystems.ReadAccessTag.Codes.ROLE) != null; } @Override @@ -307,7 +305,7 @@ public boolean hasAll(Resource resource) if (resource == null || !resource.hasMeta() || !resource.getMeta().hasTag()) return false; - return resource.getMeta().getTag(READ_ACCESS_TAG_SYSTEM, READ_ACCESS_TAG_VALUE_ALL) != null; + return resource.getMeta().getTag(CodeSystems.ReadAccessTag.SYSTEM, CodeSystems.ReadAccessTag.Codes.ALL) != null; } @Override @@ -328,16 +326,16 @@ public boolean isValid(Resource resource, Predicate organizationWith // all({LOCAL, ORGANIZATION, ROLE, ALL}) valid long tagsCount = resource.getMeta().getTag().stream().filter(Coding::hasSystem).filter(Coding::hasCode) - .filter(c -> READ_ACCESS_TAG_SYSTEM.equals(c.getSystem())) + .filter(c -> CodeSystems.ReadAccessTag.SYSTEM.equals(c.getSystem())) .filter(c -> READ_ACCESS_TAG_VALUES.contains(c.getCode())).count(); boolean local = resource.getMeta().getTag().stream().filter(Coding::hasSystem).filter(Coding::hasCode) - .filter(c -> READ_ACCESS_TAG_SYSTEM.equals(c.getSystem())) - .filter(c -> READ_ACCESS_TAG_VALUE_LOCAL.equals(c.getCode())).count() == 1; + .filter(c -> CodeSystems.ReadAccessTag.SYSTEM.equals(c.getSystem())) + .filter(c -> CodeSystems.ReadAccessTag.Codes.LOCAL.equals(c.getCode())).count() == 1; boolean all = resource.getMeta().getTag().stream().filter(Coding::hasSystem).filter(Coding::hasCode) - .filter(c -> READ_ACCESS_TAG_SYSTEM.equals(c.getSystem())) - .filter(c -> READ_ACCESS_TAG_VALUE_ALL.equals(c.getCode())).count() == 1; + .filter(c -> CodeSystems.ReadAccessTag.SYSTEM.equals(c.getSystem())) + .filter(c -> CodeSystems.ReadAccessTag.Codes.ALL.equals(c.getCode())).count() == 1; boolean tagsValid = resource.getMeta().getTag().stream().filter(Coding::hasSystem).filter(Coding::hasCode) - .filter(c -> READ_ACCESS_TAG_SYSTEM.equals(c.getSystem())) + .filter(c -> CodeSystems.ReadAccessTag.SYSTEM.equals(c.getSystem())) .filter(c -> READ_ACCESS_TAG_VALUES.contains(c.getCode())) .allMatch(isValidReadAccessTag(organizationWithIdentifierExists, roleExists)); @@ -349,12 +347,12 @@ private Predicate isValidReadAccessTag(Predicate organizatio { return coding -> switch (coding.getCode()) { - case READ_ACCESS_TAG_VALUE_LOCAL -> true; - case READ_ACCESS_TAG_VALUE_ORGANIZATION -> + case CodeSystems.ReadAccessTag.Codes.LOCAL -> true; + case CodeSystems.ReadAccessTag.Codes.ORGANIZATION -> isValidOrganizationReadAccessTag(coding, organizationWithIdentifierExists); - case READ_ACCESS_TAG_VALUE_ROLE -> + case CodeSystems.ReadAccessTag.Codes.ROLE -> isValidRoleReadAccessTag(coding, organizationWithIdentifierExists, roleExists); - case READ_ACCESS_TAG_VALUE_ALL -> true; + case CodeSystems.ReadAccessTag.Codes.ALL -> true; default -> false; }; } @@ -379,7 +377,7 @@ private boolean isValidExtensionReadAccesOrganization(Extension extension, private boolean isValidOrganizationIdentifier(Identifier identifier, Predicate organizationWithIdentifierExists) { - return identifier.hasSystem() && ORGANIZATION_IDENTIFIER_SYSTEM.equals(identifier.getSystem()) + return identifier.hasSystem() && NamingSystems.OrganizationIdentifier.SID.equals(identifier.getSystem()) && identifier.hasValue() && organizationWithIdentifierExists.test(identifier); } diff --git a/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/process/Organization.java b/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/process/Organization.java index 92a613efa..2497c1893 100644 --- a/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/process/Organization.java +++ b/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/process/Organization.java @@ -33,15 +33,6 @@ public class Organization implements Recipient, Requester { - private static final String EXTENSION_PROCESS_AUTHORIZATION_REQUESTER = "requester"; - private static final String EXTENSION_PROCESS_AUTHORIZATION_RECIPIENT = "recipient"; - - private static final String EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION = "http://dsf.dev/fhir/StructureDefinition/extension-process-authorization-organization"; - - private static final String EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER = "http://dsf.dev/fhir/StructureDefinition/extension-process-authorization-organization-practitioner"; - private static final String EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_ORGANIZATION = "organization"; - private static final String EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_PRACTITIONER_ROLE = "practitioner-role"; - private final String organizationIdentifier; private final boolean localIdentity; @@ -111,13 +102,14 @@ private boolean hasPractitionerRole(Set practitionerRoles) @Override public Extension toRecipientExtension() { - return new Extension().setUrl(EXTENSION_PROCESS_AUTHORIZATION_RECIPIENT).setValue(toCoding(false)); + return new Extension().setUrl(ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_RECIPIENT) + .setValue(toCoding(false)); } @Override public Extension toRequesterExtension() { - return new Extension().setUrl(EXTENSION_PROCESS_AUTHORIZATION_REQUESTER) + return new Extension().setUrl(ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_REQUESTER) .setValue(toCoding(needsPractitionerRole())); } @@ -129,15 +121,18 @@ private Coding toCoding(boolean needsPractitionerRole) if (needsPractitionerRole) { Extension extension = coding.addExtension() - .setUrl(EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER); - extension.addExtension(EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_ORGANIZATION, + .setUrl(ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER); + extension.addExtension( + ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_ORGANIZATION, organization); - extension.addExtension(EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_PRACTITIONER_ROLE, + extension.addExtension( + ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_PRACTITIONER_ROLE, new Coding(practitionerRoleSystem, practitionerRoleCode, null)); } else { - coding.addExtension().setUrl(EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION).setValue(organization); + coding.addExtension().setUrl(ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION) + .setValue(organization); } return coding; @@ -160,13 +155,14 @@ public Coding getProcessAuthorizationCode() @Override public boolean requesterMatches(Extension requesterExtension) { - return matches(requesterExtension, EXTENSION_PROCESS_AUTHORIZATION_REQUESTER, needsPractitionerRole()); + return matches(requesterExtension, ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_REQUESTER, + needsPractitionerRole()); } @Override public boolean recipientMatches(Extension recipientExtension) { - return matches(recipientExtension, EXTENSION_PROCESS_AUTHORIZATION_RECIPIENT, false); + return matches(recipientExtension, ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_RECIPIENT, false); } private boolean matches(Extension extension, String url, boolean needsPractitionerRole) @@ -185,15 +181,16 @@ private Predicate organizationExtensionMatches(boolean needsPractitio { if (needsPractitionerRole) { - return extension -> EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER.equals(extension.getUrl()) - && !extension.hasValue() && hasMatchingSubOrganizationExtension(extension.getExtension()) + return extension -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER + .equals(extension.getUrl()) && !extension.hasValue() + && hasMatchingSubOrganizationExtension(extension.getExtension()) && hasMatchingPractitionerExtension(extension.getExtension()); } else { - return extension -> EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION.equals(extension.getUrl()) - && extension.hasValue() && extension.getValue() instanceof Identifier value - && organizationIdentifierMatches(value); + return extension -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION + .equals(extension.getUrl()) && extension.hasValue() + && extension.getValue() instanceof Identifier value && organizationIdentifierMatches(value); } } @@ -211,8 +208,8 @@ private boolean hasMatchingSubOrganizationExtension(List extensions) private boolean subOrganizationExtensionMatches(Extension extension) { - return EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_ORGANIZATION.equals(extension.getUrl()) - && extension.hasValue() && extension.getValue() instanceof Identifier value + return ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_ORGANIZATION + .equals(extension.getUrl()) && extension.hasValue() && extension.getValue() instanceof Identifier value && organizationIdentifierMatches(value); } @@ -223,8 +220,8 @@ private boolean hasMatchingPractitionerExtension(List extensions) private boolean practitionerExtensionMatches(Extension extension) { - return EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_PRACTITIONER_ROLE.equals(extension.getUrl()) - && extension.hasValue() && extension.getValue() instanceof Coding value + return ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_PRACTITIONER_ROLE + .equals(extension.getUrl()) && extension.hasValue() && extension.getValue() instanceof Coding value && practitionerRoleMatches(value); } @@ -273,8 +270,8 @@ private static Organization from(boolean localIdentity, Coding coding, { if (coding != null && coding.hasExtension()) { - List organizations = coding.getExtension().stream().filter(Extension::hasUrl) - .filter(e -> EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION.equals(e.getUrl())) + List organizations = coding.getExtension().stream().filter(Extension::hasUrl).filter( + e -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION.equals(e.getUrl())) .collect(Collectors.toList()); if (organizations.size() == 1) { @@ -297,19 +294,20 @@ private static Optional fromPractitionerRequester(Coding coding, if (coding != null && coding.hasExtension()) { List organizationPractitioners = coding.getExtension().stream().filter(Extension::hasUrl) - .filter(e -> EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER.equals(e.getUrl())) + .filter(e -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER + .equals(e.getUrl())) .collect(Collectors.toList()); if (organizationPractitioners.size() == 1) { Extension organizationPractitioner = organizationPractitioners.get(0); List organizations = organizationPractitioner.getExtension().stream() .filter(Extension::hasUrl) - .filter(e -> EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_ORGANIZATION + .filter(e -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_ORGANIZATION .equals(e.getUrl())) .collect(Collectors.toList()); List practitionerRoles = organizationPractitioner.getExtension().stream() .filter(Extension::hasUrl) - .filter(e -> EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_PRACTITIONER_ROLE + .filter(e -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_PRACTITIONER_ROLE .equals(e.getUrl())) .collect(Collectors.toList()); if (organizations.size() == 1 && practitionerRoles.size() == 1) diff --git a/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/process/ProcessAuthorizationHelperImpl.java b/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/process/ProcessAuthorizationHelperImpl.java index 10bc2a894..3f944d2d7 100644 --- a/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/process/ProcessAuthorizationHelperImpl.java +++ b/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/process/ProcessAuthorizationHelperImpl.java @@ -35,12 +35,6 @@ public class ProcessAuthorizationHelperImpl implements ProcessAuthorizationHelper { - private static final String EXTENSION_PROCESS_AUTHORIZATION = "http://dsf.dev/fhir/StructureDefinition/extension-process-authorization"; - private static final String EXTENSION_PROCESS_AUTHORIZATION_MESSAGE_NAME = "message-name"; - private static final String EXTENSION_PROCESS_AUTHORIZATION_TASK_PROFILE = "task-profile"; - private static final String EXTENSION_PROCESS_AUTHORIZATION_REQUESTER = "requester"; - private static final String EXTENSION_PROCESS_AUTHORIZATION_RECIPIENT = "recipient"; - private static final class RecipientFactoryImpl implements RecipientFactory { @Override diff --git a/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/process/Role.java b/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/process/Role.java index e42720e87..111432cce 100644 --- a/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/process/Role.java +++ b/dsf-bpe/dsf-bpe-process-api-v2-impl/src/main/java/dev/dsf/bpe/v2/service/process/Role.java @@ -34,16 +34,6 @@ public class Role implements Recipient, Requester { - private static final String EXTENSION_PROCESS_AUTHORIZATION_REQUESTER = "requester"; - private static final String EXTENSION_PROCESS_AUTHORIZATION_RECIPIENT = "recipient"; - - private static final String EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE = "http://dsf.dev/fhir/StructureDefinition/extension-process-authorization-parent-organization-role"; - private static final String EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION = "parent-organization"; - private static final String EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE = "organization-role"; - - private static final String EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER = "http://dsf.dev/fhir/StructureDefinition/extension-process-authorization-parent-organization-role-practitioner"; - private static final String EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER_PRACTITIONER_ROLE = "practitioner-role"; - private final boolean localIdentity; private final String parentOrganizationIdentifier; private final String organizationRoleSystem; @@ -152,13 +142,14 @@ private boolean hasPractitionerRole(Set practitionerRoles) @Override public Extension toRecipientExtension() { - return new Extension().setUrl(EXTENSION_PROCESS_AUTHORIZATION_RECIPIENT).setValue(toCoding(false)); + return new Extension().setUrl(ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_RECIPIENT) + .setValue(toCoding(false)); } @Override public Extension toRequesterExtension() { - return new Extension().setUrl(EXTENSION_PROCESS_AUTHORIZATION_REQUESTER) + return new Extension().setUrl(ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_REQUESTER) .setValue(toCoding(needsPractitionerRole())); } @@ -166,27 +157,31 @@ private Coding toCoding(boolean needsPractitionerRole) { Identifier parentOrganization = OrganizationIdentifier.withValue(parentOrganizationIdentifier); Extension parentOrganizationExt = new Extension( - EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION, parentOrganization); + ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION, + parentOrganization); Coding organizationRole = new Coding(organizationRoleSystem, organizationRoleCode, null); Extension organizationRoleExt = new Extension( - EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE, organizationRole); + ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE, + organizationRole); Coding coding = getProcessAuthorizationCode(); if (needsPractitionerRole) { Extension practitionerRoleExt = new Extension( - EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER_PRACTITIONER_ROLE, + ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER_PRACTITIONER_ROLE, new Coding(practitionerRoleSystem, practitionerRoleCode, null)); - coding.addExtension().setUrl(EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER) + coding.addExtension().setUrl( + ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER) .addExtension(parentOrganizationExt).addExtension(organizationRoleExt) .addExtension(practitionerRoleExt); } else { - coding.addExtension().setUrl(EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE) + coding.addExtension() + .setUrl(ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE) .addExtension(parentOrganizationExt).addExtension(organizationRoleExt); } @@ -210,13 +205,14 @@ public Coding getProcessAuthorizationCode() @Override public boolean requesterMatches(Extension requesterExtension) { - return matches(requesterExtension, EXTENSION_PROCESS_AUTHORIZATION_REQUESTER, needsPractitionerRole()); + return matches(requesterExtension, ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_REQUESTER, + needsPractitionerRole()); } @Override public boolean recipientMatches(Extension recipientExtension) { - return matches(recipientExtension, EXTENSION_PROCESS_AUTHORIZATION_RECIPIENT, false); + return matches(recipientExtension, ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_RECIPIENT, false); } private boolean matches(Extension extension, String url, boolean needsPractitionerRole) @@ -235,7 +231,7 @@ private Predicate parentOrganizationRoleExtensionMatches(boolean need { if (needsPractitionerRole) { - return extension -> EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER + return extension -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER .equals(extension.getUrl()) && extension.hasExtension() && hasMatchingParentOrganizationExtension(extension.getExtension()) && hasMatchingOrganizationRoleExtension(extension.getExtension()) @@ -243,8 +239,9 @@ && hasMatchingOrganizationRoleExtension(extension.getExtension()) } else { - return extension -> EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE.equals(extension.getUrl()) - && extension.hasExtension() && hasMatchingParentOrganizationExtension(extension.getExtension()) + return extension -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE + .equals(extension.getUrl()) && extension.hasExtension() + && hasMatchingParentOrganizationExtension(extension.getExtension()) && hasMatchingOrganizationRoleExtension(extension.getExtension()); } } @@ -256,8 +253,8 @@ private boolean hasMatchingParentOrganizationExtension(List extension private boolean parentOrganizationExtensionMatches(Extension extension) { - return EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION.equals(extension.getUrl()) - && extension.hasValue() && extension.getValue() instanceof Identifier value + return ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION + .equals(extension.getUrl()) && extension.hasValue() && extension.getValue() instanceof Identifier value && parentOrganizationIdentifierMatches(value); } @@ -275,8 +272,8 @@ private boolean hasMatchingOrganizationRoleExtension(List extensions) private boolean organizationRoleExtensionMatches(Extension extension) { - return EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE.equals(extension.getUrl()) - && extension.hasValue() && extension.getValue() instanceof Coding value + return ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE + .equals(extension.getUrl()) && extension.hasValue() && extension.getValue() instanceof Coding value && organizationRoleMatches(value); } @@ -293,7 +290,7 @@ private boolean hasMatchingPractitionerRoleExtension(List extensions) private boolean practitionerRoleExtensionMatches(Extension extension) { - return EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER_PRACTITIONER_ROLE + return ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER_PRACTITIONER_ROLE .equals(extension.getUrl()) && extension.hasValue() && extension.getValue() instanceof Coding value && practitionerRoleMatches(value); } @@ -345,7 +342,8 @@ private static Role from(boolean localIdentity, Coding coding, if (coding != null && coding.hasExtension()) { List parentOrganizationRoles = coding.getExtension().stream().filter(Extension::hasUrl) - .filter(e -> EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE.equals(e.getUrl())) + .filter(e -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE + .equals(e.getUrl())) .collect(Collectors.toList()); if (parentOrganizationRoles.size() == 1) @@ -353,12 +351,12 @@ private static Role from(boolean localIdentity, Coding coding, Extension parentOrganizationRole = parentOrganizationRoles.get(0); List parentOrganizations = parentOrganizationRole.getExtension().stream() .filter(Extension::hasUrl) - .filter(e -> EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION + .filter(e -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION .equals(e.getUrl())) .collect(Collectors.toList()); List organizationRoles = parentOrganizationRole.getExtension().stream() .filter(Extension::hasUrl) - .filter(e -> EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE + .filter(e -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE .equals(e.getUrl())) .collect(Collectors.toList()); @@ -393,7 +391,7 @@ private static Optional fromPractitionerRequester(Coding coding, { List parentOrganizationRolePractitioners = coding.getExtension().stream() .filter(Extension::hasUrl) - .filter(e -> EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER + .filter(e -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER .equals(e.getUrl())) .collect(Collectors.toList()); @@ -402,17 +400,17 @@ private static Optional fromPractitionerRequester(Coding coding, Extension parentOrganizationRolePractitioner = parentOrganizationRolePractitioners.get(0); List parentOrganizations = parentOrganizationRolePractitioner.getExtension().stream() .filter(Extension::hasUrl) - .filter(e -> EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION + .filter(e -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION .equals(e.getUrl())) .collect(Collectors.toList()); List organizationRoles = parentOrganizationRolePractitioner.getExtension().stream() .filter(Extension::hasUrl) - .filter(e -> EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE + .filter(e -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE .equals(e.getUrl())) .collect(Collectors.toList()); List practitionerRoles = parentOrganizationRolePractitioner.getExtension().stream() .filter(Extension::hasUrl) - .filter(e -> EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER_PRACTITIONER_ROLE + .filter(e -> ProcessAuthorizationHelper.EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER_PRACTITIONER_ROLE .equals(e.getUrl())) .collect(Collectors.toList()); diff --git a/dsf-bpe/dsf-bpe-process-api-v2/src/main/java/dev/dsf/bpe/v2/service/ReadAccessHelper.java b/dsf-bpe/dsf-bpe-process-api-v2/src/main/java/dev/dsf/bpe/v2/service/ReadAccessHelper.java index 59c582eae..52f63326d 100644 --- a/dsf-bpe/dsf-bpe-process-api-v2/src/main/java/dev/dsf/bpe/v2/service/ReadAccessHelper.java +++ b/dsf-bpe/dsf-bpe-process-api-v2/src/main/java/dev/dsf/bpe/v2/service/ReadAccessHelper.java @@ -31,6 +31,12 @@ */ public interface ReadAccessHelper { + String EXTENSION_READ_ACCESS_ORGANIZATION = "http://dsf.dev/fhir/StructureDefinition/extension-read-access-organization"; + + String EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE = "http://dsf.dev/fhir/StructureDefinition/extension-read-access-parent-organization-role"; + String EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION = "parent-organization"; + String EXTENSION_READ_ACCESS_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE = "organization-role"; + /** * Adds LOCAL tag. Removes ALL tag if present. * diff --git a/dsf-bpe/dsf-bpe-process-api-v2/src/main/java/dev/dsf/bpe/v2/service/process/ProcessAuthorizationHelper.java b/dsf-bpe/dsf-bpe-process-api-v2/src/main/java/dev/dsf/bpe/v2/service/process/ProcessAuthorizationHelper.java index cc8998250..19e6420e0 100644 --- a/dsf-bpe/dsf-bpe-process-api-v2/src/main/java/dev/dsf/bpe/v2/service/process/ProcessAuthorizationHelper.java +++ b/dsf-bpe/dsf-bpe-process-api-v2/src/main/java/dev/dsf/bpe/v2/service/process/ProcessAuthorizationHelper.java @@ -27,6 +27,29 @@ public interface ProcessAuthorizationHelper { + String EXTENSION_PROCESS_AUTHORIZATION = "http://dsf.dev/fhir/StructureDefinition/extension-process-authorization"; + String EXTENSION_PROCESS_AUTHORIZATION_MESSAGE_NAME = "message-name"; + String EXTENSION_PROCESS_AUTHORIZATION_TASK_PROFILE = "task-profile"; + String EXTENSION_PROCESS_AUTHORIZATION_REQUESTER = "requester"; + String EXTENSION_PROCESS_AUTHORIZATION_RECIPIENT = "recipient"; + + String EXTENSION_PROCESS_AUTHORIZATION_PRACTITIONER = "http://dsf.dev/fhir/StructureDefinition/extension-process-authorization-practitioner"; + + String EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION = "http://dsf.dev/fhir/StructureDefinition/extension-process-authorization-organization"; + + String EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER = "http://dsf.dev/fhir/StructureDefinition/extension-process-authorization-organization-practitioner"; + String EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_ORGANIZATION = "organization"; + String EXTENSION_PROCESS_AUTHORIZATION_ORGANIZATION_PRACTITIONER_PRACTITIONER_ROLE = "practitioner-role"; + + String EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE = "http://dsf.dev/fhir/StructureDefinition/extension-process-authorization-parent-organization-role"; + String EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION = "parent-organization"; + String EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE = "organization-role"; + + String EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER = "http://dsf.dev/fhir/StructureDefinition/extension-process-authorization-parent-organization-role-practitioner"; + String EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER_PARENT_ORGANIZATION = EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PARENT_ORGANIZATION; + String EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER_ORGANIZATION_ROLE = EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_ORGANIZATION_ROLE; + String EXTENSION_PROCESS_AUTHORIZATION_PARENT_ORGANIZATION_ROLE_PRACTITIONER_PRACTITIONER_ROLE = "practitioner-role"; + interface RecipientFactory { Recipient localAll(); diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/listener/DefaultBpmnParseListener.java b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/listener/DefaultBpmnParseListener.java index 537d863ff..a8cd509da 100755 --- a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/listener/DefaultBpmnParseListener.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/listener/DefaultBpmnParseListener.java @@ -39,6 +39,7 @@ import dev.dsf.bpe.api.plugin.ProcessIdAndVersion; import dev.dsf.bpe.api.plugin.ProcessPlugin; import dev.dsf.bpe.engine.ProcessPluginConsumer; +import dev.dsf.bpe.plugin.ProcessPluginApiFactory; public class DefaultBpmnParseListener implements BpmnParseListener, ProcessPluginConsumer { @@ -75,7 +76,7 @@ private Optional getListenerFactory(ActivityImpl element) String apiVersion = withTenant.getTenantId(); if (apiVersion == null) - return Optional.empty(); + return Optional.ofNullable(listenerFactoriesByApiVersion.get(ProcessPluginApiFactory.API_V1_STRING)); else return Optional.ofNullable(listenerFactoriesByApiVersion.get(apiVersion)); } diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/plugin/ProcessPluginApiFactory.java b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/plugin/ProcessPluginApiFactory.java index 855ca5714..95b0b7ad9 100644 --- a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/plugin/ProcessPluginApiFactory.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/plugin/ProcessPluginApiFactory.java @@ -44,6 +44,11 @@ public class ProcessPluginApiFactory implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(ProcessPluginApiFactory.class); + public static final int API_V1 = 1; + public static final int API_V2 = 2; + + public static final String API_V1_STRING = "1"; + private final ConfigurableEnvironment environment; private final DsfClientConfig dsfClientConfig; private final FhirClientConfigs fhirClientConfigs; @@ -90,7 +95,7 @@ public void afterPropertiesSet() throws Exception public List initialize() { - return IntStream.of(1, 2).mapToObj(this::init).toList(); + return IntStream.of(API_V1, API_V2).mapToObj(this::init).toList(); } private ProcessPluginFactory init(int apiVersion) diff --git a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/spring/config/PropertiesConfig.java b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/spring/config/PropertiesConfig.java index 68ebdb17b..3a2a911ef 100644 --- a/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/spring/config/PropertiesConfig.java +++ b/dsf-bpe/dsf-bpe-server/src/main/java/dev/dsf/bpe/spring/config/PropertiesConfig.java @@ -92,7 +92,7 @@ public class PropertiesConfig extends AbstractCertificateConfig implements Initi @Value("${dev.dsf.bpe.server.base.url:https://localhost/bpe}") private String bpeServerBaseUrl; - @Documentation(description = "Role config YAML as defined in [FHIR Server: Access Control](access-control)") + @Documentation(description = "Role config YAML as defined in [BPE Server: Access Control](access-control)") @Value("${dev.dsf.bpe.server.roleConfig:}") private String roleConfig; diff --git a/dsf-bpe/dsf-bpe-test-plugin-v1/src/main/java/dev/dsf/bpe/test/service/AbstractTest.java b/dsf-bpe/dsf-bpe-test-plugin-v1/src/main/java/dev/dsf/bpe/test/service/AbstractTest.java index 99eb5163e..168c0c754 100644 --- a/dsf-bpe/dsf-bpe-test-plugin-v1/src/main/java/dev/dsf/bpe/test/service/AbstractTest.java +++ b/dsf-bpe/dsf-bpe-test-plugin-v1/src/main/java/dev/dsf/bpe/test/service/AbstractTest.java @@ -17,9 +17,9 @@ import java.util.function.Consumer; +import org.camunda.bpm.engine.delegate.BpmnError; +import org.camunda.bpm.engine.delegate.DelegateExecution; import org.hl7.fhir.r4.model.StringType; -import org.operaton.bpm.engine.delegate.BpmnError; -import org.operaton.bpm.engine.delegate.DelegateExecution; import dev.dsf.bpe.test.PluginTestExecutor; import dev.dsf.bpe.v1.ProcessPluginApi; diff --git a/dsf-bpe/dsf-bpe-test-plugin-v1/src/main/java/dev/dsf/bpe/test/service/ApiTest.java b/dsf-bpe/dsf-bpe-test-plugin-v1/src/main/java/dev/dsf/bpe/test/service/ApiTest.java index b9a5ab674..0cc40be27 100644 --- a/dsf-bpe/dsf-bpe-test-plugin-v1/src/main/java/dev/dsf/bpe/test/service/ApiTest.java +++ b/dsf-bpe/dsf-bpe-test-plugin-v1/src/main/java/dev/dsf/bpe/test/service/ApiTest.java @@ -17,8 +17,8 @@ import static dev.dsf.bpe.test.PluginTestExecutor.expectNotNull; -import org.operaton.bpm.engine.delegate.BpmnError; -import org.operaton.bpm.engine.delegate.DelegateExecution; +import org.camunda.bpm.engine.delegate.BpmnError; +import org.camunda.bpm.engine.delegate.DelegateExecution; import dev.dsf.bpe.test.PluginTest; import dev.dsf.bpe.v1.ProcessPluginApi; diff --git a/dsf-bpe/dsf-bpe-test-plugin-v1/src/main/java/dev/dsf/bpe/test/service/TestActivitySelector.java b/dsf-bpe/dsf-bpe-test-plugin-v1/src/main/java/dev/dsf/bpe/test/service/TestActivitySelector.java index d91572769..c08ca5c0f 100644 --- a/dsf-bpe/dsf-bpe-test-plugin-v1/src/main/java/dev/dsf/bpe/test/service/TestActivitySelector.java +++ b/dsf-bpe/dsf-bpe-test-plugin-v1/src/main/java/dev/dsf/bpe/test/service/TestActivitySelector.java @@ -15,8 +15,8 @@ */ package dev.dsf.bpe.test.service; -import org.operaton.bpm.engine.delegate.BpmnError; -import org.operaton.bpm.engine.delegate.DelegateExecution; +import org.camunda.bpm.engine.delegate.BpmnError; +import org.camunda.bpm.engine.delegate.DelegateExecution; import dev.dsf.bpe.v1.ProcessPluginApi; import dev.dsf.bpe.v1.activity.AbstractServiceDelegate; diff --git a/dsf-bpe/pom.xml b/dsf-bpe/pom.xml index f9baa1dad..95906a23e 100755 --- a/dsf-bpe/pom.xml +++ b/dsf-bpe/pom.xml @@ -30,7 +30,9 @@ dsf-bpe-process-api dsf-bpe-process-api-v1 + dsf-bpe-process-api-v1-base dsf-bpe-process-api-v1-impl + dsf-bpe-process-api-v1-operaton dsf-bpe-process-api-v2 dsf-bpe-process-api-v2-impl dsf-bpe-server @@ -73,11 +75,21 @@ dsf-bpe-process-api-v1 ${project.version} + + dev.dsf + dsf-bpe-process-api-v1-base + ${project.version} + dev.dsf dsf-bpe-process-api-v1-impl ${project.version} + + dev.dsf + dsf-bpe-process-api-v1-operaton + ${project.version} + dev.dsf dsf-bpe-process-api-v2 diff --git a/dsf-docker-dev-setup-3dic-ttp/docker-compose.yml b/dsf-docker-dev-setup-3dic-ttp/docker-compose.yml index 505cb386b..3cd1ac2b8 100644 --- a/dsf-docker-dev-setup-3dic-ttp/docker-compose.yml +++ b/dsf-docker-dev-setup-3dic-ttp/docker-compose.yml @@ -14,7 +14,6 @@ # limitations under the License. # -version: '3.8' services: proxy: image: nginx:1.29 diff --git a/dsf-docker-dev-setup/bpe/docker-compose.yml b/dsf-docker-dev-setup/bpe/docker-compose.yml index b4e2e0ba1..6d3064fed 100644 --- a/dsf-docker-dev-setup/bpe/docker-compose.yml +++ b/dsf-docker-dev-setup/bpe/docker-compose.yml @@ -14,7 +14,6 @@ # limitations under the License. # -version: '3.8' services: proxy: build: ../../dsf-docker/bpe_proxy diff --git a/dsf-docker-dev-setup/fhir/docker-compose.yml b/dsf-docker-dev-setup/fhir/docker-compose.yml index 4cfa3e7f2..973c27c27 100644 --- a/dsf-docker-dev-setup/fhir/docker-compose.yml +++ b/dsf-docker-dev-setup/fhir/docker-compose.yml @@ -14,7 +14,6 @@ # limitations under the License. # -version: '3.8' services: proxy: build: ../../dsf-docker/fhir_proxy diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/ResourceOperationOutcome.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/ResourceOperationOutcome.java index 878110944..1407b904d 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/ResourceOperationOutcome.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/adapter/ResourceOperationOutcome.java @@ -135,85 +135,96 @@ private Stream statisticsElements() String.valueOf(statistics.activityDefinitions()), ResourceType.ActivityDefinition.name() + "?_sort=status,url,version"), new Element(null, null, ResourceType.Binary.name(), ResourceType.Binary.name(), null, null, - String.valueOf(statistics.binaries()), ResourceType.Binary.name()), + String.valueOf(statistics.binaries()), ResourceType.Binary.name() + "?_sort=-_lastUpdated"), new Element(null, null, ResourceType.DocumentReference.name(), ResourceType.DocumentReference.name(), null, null, String.valueOf(statistics.documentReferences()), - ResourceType.DocumentReference.name()), + ResourceType.DocumentReference.name() + "?_sort=-_lastUpdated"), new Element("active", null, ResourceType.Endpoint.name(), ResourceType.Endpoint.name(), "active", null, - String.valueOf(statistics.endpoints()), ResourceType.Endpoint.name() + "?status=active"), + String.valueOf(statistics.endpoints()), + ResourceType.Endpoint.name() + "?status=active&_sort=address"), new Element(null, null, ResourceType.Library.name(), ResourceType.Library.name(), null, null, - String.valueOf(statistics.libraries()), ResourceType.Library.name()), + String.valueOf(statistics.libraries()), ResourceType.Library.name() + "?_sort=-_lastUpdated"), new Element(null, null, ResourceType.Measure.name(), ResourceType.Measure.name(), null, null, - String.valueOf(statistics.measures()), ResourceType.Measure.name()), + String.valueOf(statistics.measures()), ResourceType.Measure.name() + "?_sort=-_lastUpdated"), new Element(null, null, ResourceType.MeasureReport.name(), ResourceType.MeasureReport.name(), null, - null, String.valueOf(statistics.measureReports()), ResourceType.MeasureReport.name()), + null, String.valueOf(statistics.measureReports()), + ResourceType.MeasureReport.name() + "?_sort=-_lastUpdated"), new Element(null, true, ResourceType.Organization.name(), ResourceType.Organization.name(), "member, active", null, String.valueOf(statistics.organizationsMember()), ResourceType.Organization.name() - + "?_profile=http://dsf.dev/fhir/StructureDefinition/organization"), + + "?_profile=http://dsf.dev/fhir/StructureDefinition/organization&_sort=identifier"), new Element(null, true, ResourceType.Organization.name(), ResourceType.Organization.name(), "parent, active", null, String.valueOf(statistics.organizationsParent()), ResourceType.Organization.name() - + "?_profile=http://dsf.dev/fhir/StructureDefinition/organization-parent"), + + "?_profile=http://dsf.dev/fhir/StructureDefinition/organization-parent&_sort=identifier"), new Element(null, true, ResourceType.OrganizationAffiliation.name(), ResourceType.OrganizationAffiliation.name(), "active", null, String.valueOf(statistics.organizationAffiliations()), - ResourceType.OrganizationAffiliation + "?active=true"), + ResourceType.OrganizationAffiliation + "?active=true&_sort=-_lastUpdated"), new Element("in-progress", null, ResourceType.QuestionnaireResponse.name(), ResourceType.QuestionnaireResponse.name(), "in-progress", "24h", String.valueOf(statistics.questionnaireResponsesInProgress24h()), - ResourceType.QuestionnaireResponse.name() + "?status=in-progress&_lastUpdated=ge" - + minusOneDay), + ResourceType.QuestionnaireResponse.name() + "?status=in-progress&_lastUpdated=ge" + minusOneDay + + "&_sort=-_lastUpdated"), new Element("amended", null, ResourceType.QuestionnaireResponse.name(), ResourceType.QuestionnaireResponse.name(), "amended", "24h", String.valueOf(statistics.questionnaireResponsesAmended24h()), - ResourceType.QuestionnaireResponse.name() + "?status=amended&_lastUpdated=ge" + minusOneDay), + ResourceType.QuestionnaireResponse.name() + "?status=amended&_lastUpdated=ge" + minusOneDay + + "&_sort=-_lastUpdated"), new Element("in-progress", null, ResourceType.QuestionnaireResponse.name(), ResourceType.QuestionnaireResponse.name(), "in-progress", "30d", String.valueOf(statistics.questionnaireResponsesInProgress30d()), ResourceType.QuestionnaireResponse.name() + "?status=in-progress&_lastUpdated=ge" - + minusThirtyDays), + + minusThirtyDays + "&_sort=-_lastUpdated"), new Element("amended", null, ResourceType.QuestionnaireResponse.name(), ResourceType.QuestionnaireResponse.name(), "amended", "30d", String.valueOf(statistics.questionnaireResponsesAmended30d()), - ResourceType.QuestionnaireResponse.name() + "?status=amended&_lastUpdated=ge" - + minusThirtyDays), + ResourceType.QuestionnaireResponse.name() + "?status=amended&_lastUpdated=ge" + minusThirtyDays + + "&_sort=-_lastUpdated"), new Element("in-progress", null, ResourceType.QuestionnaireResponse.name(), ResourceType.QuestionnaireResponse.name(), "in-progress", null, String.valueOf(statistics.questionnaireResponsesInProgress()), - ResourceType.QuestionnaireResponse.name() + "?status=in-progress"), + ResourceType.QuestionnaireResponse.name() + "?status=in-progress&_sort=-_lastUpdated"), new Element("amended", null, ResourceType.QuestionnaireResponse.name(), ResourceType.QuestionnaireResponse.name(), "amended", null, String.valueOf(statistics.questionnaireResponsesAmended()), - ResourceType.QuestionnaireResponse.name() + "?status=amended"), + ResourceType.QuestionnaireResponse.name() + "?status=amended&_sort=-_lastUpdated"), new Element("draft", null, ResourceType.Task.name(), ResourceType.Task.name(), "draft", null, String.valueOf(statistics.tasksDraft()), ResourceType.Task.name() + "?status=draft&_sort=_profile,identifier"), new Element("in-progress", null, ResourceType.Task.name(), ResourceType.Task.name(), "in-progress", "24h", String.valueOf(statistics.tasksInProgress24h()), - ResourceType.Task.name() + "?status=in-progress&_lastUpdated=ge" + minusOneDay), + ResourceType.Task.name() + "?status=in-progress&_lastUpdated=ge" + minusOneDay + + "&_sort=-_lastUpdated"), new Element("completed", null, ResourceType.Task.name(), ResourceType.Task.name(), "completed", "24h", String.valueOf(statistics.tasksCompleted24h()), - ResourceType.Task.name() + "?status=completed&_lastUpdated=ge" + minusOneDay), + ResourceType.Task.name() + "?status=completed&_lastUpdated=ge" + minusOneDay + + "&_sort=-_lastUpdated"), new Element("failed", null, ResourceType.Task.name(), ResourceType.Task.name(), "failed", "24h", String.valueOf(statistics.tasksFailed24h()), - ResourceType.Task.name() + "?status=failed&_lastUpdated=ge" + minusOneDay), + ResourceType.Task.name() + "?status=failed&_lastUpdated=ge" + minusOneDay + + "&_sort=-_lastUpdated"), new Element("in-progress", null, ResourceType.Task.name(), ResourceType.Task.name(), "in-progress", "30d", String.valueOf(statistics.tasksInProgress30d()), - ResourceType.Task.name() + "?status=in-progress&_lastUpdated=ge" + minusThirtyDays), + ResourceType.Task.name() + "?status=in-progress&_lastUpdated=ge" + minusThirtyDays + + "&_sort=-_lastUpdated"), new Element("completed", null, ResourceType.Task.name(), ResourceType.Task.name(), "completed", "30d", String.valueOf(statistics.tasksCompleted30d()), - ResourceType.Task.name() + "?status=completed&_lastUpdated=ge" + minusThirtyDays), + ResourceType.Task.name() + "?status=completed&_lastUpdated=ge" + minusThirtyDays + + "&_sort=-_lastUpdated"), new Element("failed", null, ResourceType.Task.name(), ResourceType.Task.name(), "failed", "30d", String.valueOf(statistics.tasksFailed30d()), - ResourceType.Task.name() + "?status=failed&_lastUpdated=ge" + minusThirtyDays), + ResourceType.Task.name() + "?status=failed&_lastUpdated=ge" + minusThirtyDays + + "&_sort=-_lastUpdated"), new Element("in-progress", null, ResourceType.Task.name(), ResourceType.Task.name(), "in-progress", null, String.valueOf(statistics.tasksInProgress()), - ResourceType.Task.name() + "?status=in-progress"), + ResourceType.Task.name() + "?status=in-progress&_sort=-_lastUpdated"), new Element("completed", null, ResourceType.Task.name(), ResourceType.Task.name(), "completed", null, - String.valueOf(statistics.tasksCompleted()), ResourceType.Task.name() + "?status=completed"), + String.valueOf(statistics.tasksCompleted()), + ResourceType.Task.name() + "?status=completed&_sort=-_lastUpdated"), new Element("failed", null, ResourceType.Task.name(), ResourceType.Task.name(), "failed", null, - String.valueOf(statistics.tasksFailed()), ResourceType.Task.name() + "?status=failed")); + String.valueOf(statistics.tasksFailed()), + ResourceType.Task.name() + "?status=failed&_sort=-_lastUpdated")); } private ByteSize formatBytes(long bytes) diff --git a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/parameters/basic/AbstractDateTimeParameter.java b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/parameters/basic/AbstractDateTimeParameter.java index 86a47de4b..1703cc3f3 100755 --- a/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/parameters/basic/AbstractDateTimeParameter.java +++ b/dsf-fhir/dsf-fhir-server/src/main/java/dev/dsf/fhir/search/parameters/basic/AbstractDateTimeParameter.java @@ -271,7 +271,7 @@ public String getFilterQuery() private String getDateTimeQuery(String operator) { - return "(" + timestampColumn + ")::timestamp " + operator + " ?"; + return "(" + timestampColumn + ")::timestamptz " + operator + " ?"; } private String getDateQuery(String operator) @@ -377,6 +377,6 @@ private boolean matches(LocalDate lastUpdated, LocalDatePair value) @Override protected String getSortSql(String sortDirectionWithSpacePrefix) { - return "(" + timestampColumn + ")::timestamp" + sortDirectionWithSpacePrefix; + return "(" + timestampColumn + ")::timestamptz" + sortDirectionWithSpacePrefix; } } diff --git a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/db/db.binaries.changelog-2.0.0.xml b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/db/db.binaries.changelog-2.0.0.xml index 51084caaf..a8009284e 100644 --- a/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/db/db.binaries.changelog-2.0.0.xml +++ b/dsf-fhir/dsf-fhir-server/src/main/resources/fhir/db/db.binaries.changelog-2.0.0.xml @@ -22,6 +22,7 @@ logicalFilePath="db/db.binaries.changelog-2.0.0.xml"> + 9:0dde1d3e22c313b9449712244c788771 CREATE EXTENSION IF NOT EXISTS lo; @@ -39,7 +40,7 @@ GRANT UPDATE ON TABLE binaries TO ${db.server_permanent_delete_users_group}; GRANT ${db.server_permanent_delete_user} TO ${db.liquibase_user}; SET ROLE ${db.server_permanent_delete_user}; - UPDATE binaries SET binary_oid = lo_from_bytea(0, binary_data) WHERE binary_data IS NOT NULL; + UPDATE binaries SET binary_oid = lo_from_bytea(0, COALESCE(binary_data, ''::bytea)); DO ' DECLARE lo_oid oid; diff --git a/dsf-fhir/dsf-fhir-validation/src/main/java/dev/dsf/fhir/validation/ResourceValidatorImpl.java b/dsf-fhir/dsf-fhir-validation/src/main/java/dev/dsf/fhir/validation/ResourceValidatorImpl.java index 062737dd6..04ea8da50 100755 --- a/dsf-fhir/dsf-fhir-validation/src/main/java/dev/dsf/fhir/validation/ResourceValidatorImpl.java +++ b/dsf-fhir/dsf-fhir-validation/src/main/java/dev/dsf/fhir/validation/ResourceValidatorImpl.java @@ -82,10 +82,17 @@ else if (url != null && (url.startsWith("http://") || url.startsWith("https://") return true; else if (path != null && (path.startsWith("ActivityDefinition") || path.startsWith("Binary") || path.startsWith("Bundle") || path.startsWith("CodeSystem") - || path.startsWith("DocumentReference") || path.startsWith("Endpoint") || path.startsWith("Library") - || path.startsWith("Organization") || path.startsWith("QuestionnaireResponse") - || path.startsWith("ResearchStudy") || path.startsWith("StructureDefinition") - || path.startsWith("Task"))) + || path.startsWith("DocumentReference") || path.startsWith("ElementDefinition") + || path.startsWith("Endpoint") || path.startsWith("Extension") || path.startsWith("Group") + || path.startsWith("HealthcareService") || path.startsWith("Library") || path.startsWith("Location") + || path.startsWith("Measure") || path.startsWith("MeasureReport") || path.startsWith("NamingSystem") + || path.startsWith("Organization") || path.startsWith("OrganizationAffiliation") + || path.startsWith("Patient") || path.startsWith("Practitioner") + || path.startsWith("PractitionerRole") || path.startsWith("Provenance") + || path.startsWith("Questionnaire") || path.startsWith("QuestionnaireResponse") + || path.startsWith("Reference") || path.startsWith("ResearchStudy") + || path.startsWith("StructureDefinition") || path.startsWith("Subscription") + || path.startsWith("Task") || path.startsWith("ValueSet"))) return true; logger.debug("Not resolving [path: {}, url: {}, type: {}, canonical: {}]", path, url, type, canonical); diff --git a/dsf-fhir/dsf-fhir-validation/src/main/resources/fhir/StructureDefinition/dsf-task-2.0.0.xml b/dsf-fhir/dsf-fhir-validation/src/main/resources/fhir/StructureDefinition/dsf-task-2.0.0.xml index af2dc8b20..84e8cf544 100644 --- a/dsf-fhir/dsf-fhir-validation/src/main/resources/fhir/StructureDefinition/dsf-task-2.0.0.xml +++ b/dsf-fhir/dsf-fhir-validation/src/main/resources/fhir/StructureDefinition/dsf-task-2.0.0.xml @@ -72,6 +72,7 @@ + diff --git a/dsf-maven/dsf-maven-plugin/pom.xml b/dsf-maven/dsf-maven-plugin/pom.xml index 1f03c70fe..3978b20ec 100644 --- a/dsf-maven/dsf-maven-plugin/pom.xml +++ b/dsf-maven/dsf-maven-plugin/pom.xml @@ -57,8 +57,24 @@ dsf-bpe-process-api-v1 - * - * + org.camunda.bpm + camunda-engine + + + org.springframework + spring-context + + + com.fasterxml.jackson.core + jackson-databind + + + com.sun.mail + jakarta.mail + + + jakarta.ws.rs + jakarta.ws.rs-api diff --git a/dsf-maven/dsf-maven-plugin/src/main/java/dev/dsf/maven/bundle/BundleGenerator.java b/dsf-maven/dsf-maven-plugin/src/main/java/dev/dsf/maven/bundle/BundleGenerator.java index bb6dfd484..577b3a1ad 100755 --- a/dsf-maven/dsf-maven-plugin/src/main/java/dev/dsf/maven/bundle/BundleGenerator.java +++ b/dsf-maven/dsf-maven-plugin/src/main/java/dev/dsf/maven/bundle/BundleGenerator.java @@ -303,6 +303,9 @@ private Predicate>> hasSingleCycle( Set dependencies = resourcesAndDirectDependencies.get(entry.getKey()); return !dependencies.isEmpty() && dependencies.stream().flatMap(d -> { + if (d != null && d.startsWith("http://hl7.org/fhir/StructureDefinition")) + return Stream.of(); // ignore base profiles from hl7 + Set set = resourcesAndDirectDependencies.get(new EntryAndLabel(null, d)); if (set == null) { diff --git a/pom.xml b/pom.xml index 06331cff8..39d9656ef 100755 --- a/pom.xml +++ b/pom.xml @@ -43,13 +43,13 @@ 12.1.4 3.1.11 2.2.1 - 6.2.13 + 6.2.14 2.20.1 1.0.0 5.1.0 - 8.4.0 + 8.4.1 6.5.27 - 8.4.0 + 8.4.1 1.82 3.8.0 5.2.0 @@ -407,7 +407,7 @@ org.tukaani xz - 1.10 + 1.11 @@ -528,7 +528,8 @@ org.apache.maven.plugins maven-jar-plugin - 3.5.0 + + 3.4.2 @@ -620,7 +621,7 @@ com.github.spotbugs spotbugs-maven-plugin - 4.9.8.1 + 4.9.8.2 org.apache.maven.plugins @@ -647,6 +648,11 @@ license-maven-plugin 5.0.0 + + org.apache.maven.plugins + maven-shade-plugin + 3.6.1 + dev.dsf dsf-maven-plugin @@ -1289,7 +1295,9 @@ DSF 2.x dsf-bpe-process-api + dsf-bpe-process-api-v1-base dsf-bpe-process-api-v1-impl + dsf-bpe-process-api-v1-operaton dsf-bpe-process-api-v2-impl dsf-bpe-server dsf-bpe-server-jetty