diff --git a/README.md b/README.md
index 0d055bce..be2f66d6 100644
--- a/README.md
+++ b/README.md
@@ -2,6 +2,9 @@
In this repository you will find the ping-pong process for connection testing, which can be deployed on the [DSF](https://github.com/datasharingframework/dsf).
+## Version 2.x release
+Version 2.x of the ping-pong process (dubbed "Fat-Ping") includes the ability to test whether downloading FHIR resources from other DSF instances is possible. This also includes approximately measuring the network speed of resource downloads with larger download sizes (~100MB) returning more accurate results. It retains the ability to make connection tests without downloading resource like ping-pong 1.x. Documentation on configuration is available in the [wiki](https://github.com/datasharingframework/dsf-process-ping-pong/wiki).
+
## Development
Branching follows the git-flow model, for the latest development version see branch [develop](https://github.com/datasharingframework/dsf-process-ping-pong/tree/develop).
diff --git a/pom.xml b/pom.xml
index 180ae42d..0904d48a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
dev.dsf
dsf-process-ping-pong
- 1.0.1.0-SNAPSHOT
+ 2.0.0.0-RC2
jar
@@ -13,7 +13,7 @@
17
17
- 1.2.0-RC1
+ 1.2.0
../dsf
diff --git a/src/main/java/dev/dsf/bpe/ConstantsPing.java b/src/main/java/dev/dsf/bpe/ConstantsPing.java
index 0f8c12f1..2eb4057e 100644
--- a/src/main/java/dev/dsf/bpe/ConstantsPing.java
+++ b/src/main/java/dev/dsf/bpe/ConstantsPing.java
@@ -1,59 +1,188 @@
package dev.dsf.bpe;
+import java.util.List;
-public interface ConstantsPing
+import jakarta.ws.rs.core.MediaType;
+
+public final class ConstantsPing
{
- String PROCESS_NAME_PING_AUTOSTART = "pingAutostart";
- String PROCESS_NAME_PING = "ping";
- String PROCESS_NAME_PONG = "pong";
-
- String PROCESS_NAME_FULL_PING_AUTOSTART = "dsfdev_" + PROCESS_NAME_PING_AUTOSTART;
- String PROCESS_NAME_FULL_PING = "dsfdev_" + PROCESS_NAME_PING;
- String PROCESS_NAME_FULL_PONG = "dsfdev_" + PROCESS_NAME_PONG;
-
- String PROCESS_DSF_URI_BASE = "http://dsf.dev/bpe/Process/";
-
- String PROFILE_DSF_TASK_START_PING_AUTOSTART = "http://dsf.dev/fhir/StructureDefinition/task-start-ping-autostart";
- String PROFILE_DSF_TASK_START_PING_AUTOSTART_PROCESS_URI = PROCESS_DSF_URI_BASE + PROCESS_NAME_PING_AUTOSTART;
- String PROFILE_DSF_TASK_START_PING_AUTOSTART_MESSAGE_NAME = "startPingAutostart";
-
- String PROFILE_DSF_TASK_STOP_PING_AUTOSTART = "http://dsf.dev/fhir/StructureDefinition/task-stop-ping-autostart";
- String PROFILE_DSF_TASK_STOP_PING_AUTOSTART_PROCESS_URI = PROCESS_DSF_URI_BASE + PROCESS_NAME_PING_AUTOSTART;
- String PROFILE_DSF_TASK_STOP_PING_AUTOSTART_MESSAGE_NAME = "stopPingAutostart";
-
- String PROFILE_DSF_TASK_START_PING = "http://dsf.dev/fhir/StructureDefinition/task-start-ping";
- String PROFILE_DSF_TASK_START_PING_MESSAGE_NAME = "startPing";
-
- String PROFILE_DSF_TASK_PING = "http://dsf.dev/fhir/StructureDefinition/task-ping";
- String PROFILE_DSF_TASK_PING_PROCESS_URI = PROCESS_DSF_URI_BASE + PROCESS_NAME_PING;
- String PROFILE_DSF_TASK_PING_MESSAGE_NAME = "ping";
-
- String PROFILE_DSF_TASK_PONG_TASK = "http://dsf.dev/fhir/StructureDefinition/task-pong";
- String PROFILE_DSF_TASK_PONG_PROCESS_URI = PROCESS_DSF_URI_BASE + PROCESS_NAME_PONG;
- String PROFILE_DSF_TASK_PONG_MESSAGE_NAME = "pong";
-
- String CODESYSTEM_DSF_PING = "http://dsf.dev/fhir/CodeSystem/ping";
- String CODESYSTEM_DSF_PING_VALUE_PING_STATUS = "ping-status";
- String CODESYSTEM_DSF_PING_VALUE_PONG_STATUS = "pong-status";
- String CODESYSTEM_DSF_PING_VALUE_ENDPOINT_IDENTIFIER = "endpoint-identifier";
- String CODESYSTEM_DSF_PING_VALUE_TARGET_ENDPOINTS = "target-endpoints";
- String CODESYSTEM_DSF_PING_VALUE_TIMER_INTERVAL = "timer-interval";
-
- String CODESYSTEM_DSF_PING_STATUS = "http://dsf.dev/fhir/CodeSystem/ping-status";
- String CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_ALLOWED = "not-allowed";
- String CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_REACHABLE = "not-reachable";
- String CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_MISSING = "pong-missing";
- String CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_RECEIVED = "pong-received";
- String CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_SEND = "pong-send";
-
- String EXTENSION_URL_PING_STATUS = "http://dsf.dev/fhir/StructureDefinition/extension-ping-status";
- String EXTENSION_URL_CORRELATION_KEY = "correlation-key";
- String EXTENSION_URL_ORGANIZATION_IDENTIFIER = "organization-identifier";
- String EXTENSION_URL_ENDPOINT_IDENTIFIER = "endpoint-identifier";
- String EXTENSION_URL_ERROR_MESSAGE = "error-message";
-
- String BPMN_EXECUTION_VARIABLE_TIMER_INTERVAL = "timerInterval";
- String BPMN_EXECUTION_VARIABLE_STOP_TIMER = "stopTimer";
-
- String TIMER_INTERVAL_DEFAULT_VALUE = "PT24H";
+ private ConstantsPing()
+ {
+ }
+
+ public static final String PROCESS_NAME_PING_AUTOSTART = "pingAutostart";
+ public static final String PROCESS_NAME_PING = "ping";
+ public static final String PROCESS_NAME_PONG = "pong";
+
+ public static final String PROCESS_NAME_FULL_PING_AUTOSTART = "dsfdev_" + PROCESS_NAME_PING_AUTOSTART;
+ public static final String PROCESS_NAME_FULL_PING = "dsfdev_" + PROCESS_NAME_PING;
+ public static final String PROCESS_NAME_FULL_PONG = "dsfdev_" + PROCESS_NAME_PONG;
+
+ public static final String PROCESS_DSF_URI_BASE = "http://dsf.dev/bpe/Process/";
+
+ public static final String PROFILE_DSF_TASK_START_PING_AUTOSTART = "http://dsf.dev/fhir/StructureDefinition/task-start-ping-autostart";
+ public static final String PROFILE_DSF_TASK_START_PING_AUTOSTART_PROCESS_URI = PROCESS_DSF_URI_BASE
+ + PROCESS_NAME_PING_AUTOSTART;
+ public static final String PROFILE_DSF_TASK_START_PING_AUTOSTART_MESSAGE_NAME = "startPingAutostart";
+
+ public static final String PROFILE_DSF_TASK_STOP_PING_AUTOSTART = "http://dsf.dev/fhir/StructureDefinition/task-stop-ping-autostart";
+ public static final String PROFILE_DSF_TASK_STOP_PING_AUTOSTART_PROCESS_URI = PROCESS_DSF_URI_BASE
+ + PROCESS_NAME_PING_AUTOSTART;
+ public static final String PROFILE_DSF_TASK_STOP_PING_AUTOSTART_MESSAGE_NAME = "stopPingAutostart";
+
+ public static final String PROFILE_DSF_TASK_START_PING = "http://dsf.dev/fhir/StructureDefinition/task-start-ping";
+ public static final String PROFILE_DSF_TASK_START_PING_MESSAGE_NAME = "startPing";
+
+ public static final String PROFILE_DSF_TASK_PING = "http://dsf.dev/fhir/StructureDefinition/task-ping";
+ public static final String PROFILE_DSF_TASK_PING_PROCESS_URI = PROCESS_DSF_URI_BASE + PROCESS_NAME_PING;
+ public static final String PROFILE_DSF_TASK_PING_MESSAGE_NAME = "ping";
+
+ public static final String PROFILE_DSF_TASK_PONG_TASK = "http://dsf.dev/fhir/StructureDefinition/task-pong";
+ public static final String PROFILE_DSF_TASK_PONG_PROCESS_URI = PROCESS_DSF_URI_BASE + PROCESS_NAME_PONG;
+ public static final String PROFILE_DSF_TASK_PONG_MESSAGE_NAME = "pong";
+
+ public static final String PROFILE_DSF_TASK_CLEANUP_PONG = "http://dsf.dev/fhir/StructureDefinition/task-cleanup-pong";
+ public static final String PROFILE_DSF_TASK_CLEANUP_PONG_PROCESS_URI = PROCESS_DSF_URI_BASE + PROCESS_NAME_PONG;
+ public static final String PROFILE_DSF_TASK_CLEANUP_PONG_MESSAGE_NAME = "cleanupPong";
+
+ public static final String CODESYSTEM_DSF_PING = "http://dsf.dev/fhir/CodeSystem/ping-v2";
+ public static final String CODESYSTEM_DSF_PING_VALUE_PING_STATUS = "ping-status";
+ public static final String CODESYSTEM_DSF_PING_VALUE_PONG_STATUS = "pong-status";
+ public static final String CODESYSTEM_DSF_PING_VALUE_ENDPOINT_IDENTIFIER = "endpoint-identifier";
+ public static final String CODESYSTEM_DSF_PING_VALUE_TARGET_ENDPOINTS = "target-endpoints";
+ public static final String CODESYSTEM_DSF_PING_VALUE_TIMER_INTERVAL = "timer-interval";
+ public static final String CODESYSTEM_DSF_PING_VALUE_DOWNLOAD_RESOURCE_SIZE_BYTES = "download-resource-size-bytes";
+ public static final String CODESYSTEM_DSF_PING_VALUE_DOWNLOADED_DURATION_MILLIS = "downloaded-duration-millis";
+ public static final String CODESYSTEM_DSF_PING_VALUE_DOWNLOADED_BYTES = "downloaded-bytes";
+ public static final String CODESYSTEM_DSF_PING_VALUE_DOWNLOAD_RESOURCE_REFERENCE = "download-resource-reference";
+
+ public static final String CODESYSTEM_DSF_PING_STATUS = "http://dsf.dev/fhir/CodeSystem/ping-status-v2";
+ public static final String CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_ALLOWED = "not-allowed";
+ public static final String CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_REACHABLE = "not-reachable";
+ public static final String CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_MISSING = "pong-missing";
+ public static final String CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_RECEIVED = "pong-received";
+ public static final String CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_SENT = "pong-sent";
+ public static final String CODESYSTEM_DSF_PING_STATUS_VALUE_ERROR_MESSAGE = "error-message";
+ public static final String CODESYSTEM_DSF_PING_STATUS_VALUE_RESOURCE_DOWNLOADED = "resource-downloaded";
+
+ public static final String CODESYSTEM_DSF_PING_UNITS = "http://dsf.dev/fhir/CodeSystem/ping-units-v2";
+ public static final String CODESYSTEM_DSF_PING_UNITS_VALUE_BITS_PER_SECOND = "bits-per-second";
+ public static final String CODESYSTEM_DSF_PING_UNITS_VALUE_BYTES_PER_SECOND = "bytes-per-second";
+ public static final String CODESYSTEM_DSF_PING_UNITS_VALUE_MEGABITS_PER_SECOND = "megabits-per-second";
+ public static final String CODESYSTEM_DSF_PING_UNITS_VALUE_MEGABYTES_PER_SECOND = "megabytes-per-second";
+
+ public static final List CODESYSTEM_DSF_PING_UNITS_VALUES = List.of(
+ CODESYSTEM_DSF_PING_UNITS_VALUE_BITS_PER_SECOND, CODESYSTEM_DSF_PING_UNITS_VALUE_BYTES_PER_SECOND,
+ CODESYSTEM_DSF_PING_UNITS_VALUE_MEGABITS_PER_SECOND, CODESYSTEM_DSF_PING_UNITS_VALUE_MEGABYTES_PER_SECOND);
+
+ public static final String CODESYSTEM_READ_ACCESS_TAG = "http://dsf.dev/fhir/CodeSystem/read-access-tag";
+ public static final String CODESYSTEM_READ_ACCESS_TAG_VALUE_ALL = "ALL";
+
+ public static final String EXTENSION_URL_PING_STATUS = "http://dsf.dev/fhir/StructureDefinition/extension-ping-status-v2";
+ public static final String EXTENSION_URL_NETWORK_SPEED = "http://dsf.dev/fhir/StructureDefinition/extension-network-speed";
+ public static final String EXTENSION_URL_CORRELATION_KEY = "correlation-key";
+ public static final String EXTENSION_URL_ORGANIZATION_IDENTIFIER = "organization-identifier";
+ public static final String EXTENSION_URL_ENDPOINT_IDENTIFIER = "endpoint-identifier";
+ public static final String EXTENSION_URL_ERROR_MESSAGE = "error-message";
+ public static final String EXTENSION_URL_DOWNLOAD_SPEED = "download-speed";
+ public static final String EXTENSION_URL_UPLOAD_SPEED = "upload-speed";
+ public static final String EXTENSION_URL_NETWORK_SPEED_UNIT = "unit";
+ public static final String EXTENSION_URL_NETWORK_SPEED_VALUE = "network-speed";
+
+ public static final String BPMN_EXECUTION_VARIABLE_TIMER_INTERVAL = "timerInterval";
+ public static final String BPMN_EXECUTION_VARIABLE_STOP_TIMER = "stopTimer";
+ public static final String BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_SIZE_BYTES = "downloadResourceSizeBytes";
+ public static final String BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE = "downloadResource";
+ public static final String BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_REFERENCE = "downloadResourceReference";
+ private static final String BPMN_EXECUTION_VARIABLE_STATUS_CODE = "statusCode";
+ private static final String BPMN_EXECUTION_VARIABLE_ERROR_MESSAGE = "errorMessage";
+ private static final String BPMN_EXECUTION_VARIABLE_ERROR_MESSAGE_LIST = "errorMessages";
+ private static final String BPMN_EXECUTION_VARIABLE_DOWNLOADED_BYTES = "downloadedBytes";
+ private static final String BPMN_EXECUTION_VARIABLE_DOWNLOADED_DURATION_MILLIS = "downloadedDurationMillis";
+ public static final String BPMN_EXECUTION_VARIABLE_PONG_TARGET_ENDPOINT_IDENTIFIER = "targetEndpointIdentifier";
+ private static final String BPMN_EXECUTION_VARIABLE_UPLOADED_BYTES = "uploadedBytes";
+ private static final String BPMN_EXECUTION_VARIABLE_UPLOADED_DURATION_MILLIS = "uploadedDurationMillis";
+ public static final String BPMN_EXECUTION_VARIABLE_RESOURCE_DOWNLOAD_ERROR_MESSAGE = "resourceDownloadErrorMessage";
+ public static final String BPMN_EXECUTION_VARIABLE_RESOURCE_UPLOAD_ERROR_MESSAGE = "resourceUploadErrorMessage";
+
+ public static final String BPMN_ERROR_CODE_RESOURCE_DOWNLOAD_ERROR = "resourceDownloadError";
+ public static final String BPMN_ERROR_CODE_RESOURCE_UPLOAD_ERROR = "resourceUploadError";
+
+ public static final String PONG_ERROR_MESSAGE_CLEANUP_TIMEOUT = "Timeout while waiting for cleanup message";
+
+ public static final int DOWNLOAD_RESOURCE_SIZE_BYTES_DEFAULT = 10000000;
+
+ public static final MediaType DOWNLOAD_RESOURCE_MIME_TYPE = MediaType.APPLICATION_OCTET_STREAM_TYPE;
+
+ public static final String TIMER_INTERVAL_DEFAULT_VALUE = "PT24H";
+
+ public static String getBpmnExecutionVariableStatusCode()
+ {
+ return BPMN_EXECUTION_VARIABLE_STATUS_CODE;
+ }
+
+ public static String getBpmnExecutionVariableStatusCode(String correlationKey)
+ {
+ return BPMN_EXECUTION_VARIABLE_STATUS_CODE + "_" + correlationKey;
+ }
+
+ public static String getBpmnExecutionVariableErrorMessage()
+ {
+ return BPMN_EXECUTION_VARIABLE_ERROR_MESSAGE;
+ }
+
+ public static String getBpmnExecutionVariableErrorMessage(String correlationKey)
+ {
+ return BPMN_EXECUTION_VARIABLE_ERROR_MESSAGE + "_" + correlationKey;
+ }
+
+ public static String getBpmnExecutionVariableDownloadedBytes()
+ {
+ return BPMN_EXECUTION_VARIABLE_DOWNLOADED_BYTES;
+ }
+
+ public static String getBpmnExecutionVariableDownloadedBytes(String correlationKey)
+ {
+ return BPMN_EXECUTION_VARIABLE_DOWNLOADED_BYTES + "_" + correlationKey;
+ }
+
+ public static String getBpmnExecutionVariableDownloadedDurationMillis()
+ {
+ return BPMN_EXECUTION_VARIABLE_DOWNLOADED_DURATION_MILLIS;
+ }
+
+ public static String getBpmnExecutionVariableDownloadedDurationMillis(String correlationKey)
+ {
+ return BPMN_EXECUTION_VARIABLE_DOWNLOADED_DURATION_MILLIS + "_" + correlationKey;
+ }
+
+ public static String getBpmnExecutionVariableUploadedBytes()
+ {
+ return BPMN_EXECUTION_VARIABLE_UPLOADED_BYTES;
+ }
+
+ public static String getBpmnExecutionVariableUploadedBytes(String correlationKey)
+ {
+ return BPMN_EXECUTION_VARIABLE_UPLOADED_BYTES + "_" + correlationKey;
+ }
+
+ public static String getBpmnExecutionVariableUploadedDurationMillis()
+ {
+ return BPMN_EXECUTION_VARIABLE_UPLOADED_DURATION_MILLIS;
+ }
+
+ public static String getBpmnExecutionVariableUploadedDurationMillis(String correlationKey)
+ {
+ return BPMN_EXECUTION_VARIABLE_UPLOADED_DURATION_MILLIS + "_" + correlationKey;
+ }
+
+ public static String getBpmnExecutionVariableErrorMessageList()
+ {
+ return BPMN_EXECUTION_VARIABLE_ERROR_MESSAGE_LIST;
+ }
+
+ public static String getBpmnExecutionVariableErrorMessageList(String correlationKey)
+ {
+ return getBpmnExecutionVariableErrorMessageList() + "_" + correlationKey;
+ }
}
diff --git a/src/main/java/dev/dsf/bpe/PingProcessPluginDefinition.java b/src/main/java/dev/dsf/bpe/PingProcessPluginDefinition.java
index 1cf39ba8..0a1b65b8 100644
--- a/src/main/java/dev/dsf/bpe/PingProcessPluginDefinition.java
+++ b/src/main/java/dev/dsf/bpe/PingProcessPluginDefinition.java
@@ -10,8 +10,8 @@
public class PingProcessPluginDefinition implements ProcessPluginDefinition
{
- public static final String VERSION = "1.0.1.0";
- public static final LocalDate RELEASE_DATE = LocalDate.of(2023, 9, 5);
+ public static final String VERSION = "2.0.0.0";
+ public static final LocalDate RELEASE_DATE = LocalDate.of(2023, 9, 12);
@Override
public String getName()
@@ -52,6 +52,7 @@ public Map> getFhirResourcesByProcessId()
var cPing = "fhir/CodeSystem/dsf-ping.xml";
var cPingStatus = "fhir/CodeSystem/dsf-ping-status.xml";
+ var cPingUnits = "fhir/CodeSystem/dsf-ping-units.xml";
var sPingStatus = "fhir/StructureDefinition/dsf-extension-ping-status.xml";
var sPing = "fhir/StructureDefinition/dsf-task-ping.xml";
@@ -59,22 +60,25 @@ public Map> getFhirResourcesByProcessId()
var sStartPing = "fhir/StructureDefinition/dsf-task-start-ping.xml";
var sStartPingAutostart = "fhir/StructureDefinition/dsf-task-start-ping-autostart.xml";
var sStopPingAutostart = "fhir/StructureDefinition/dsf-task-stop-ping-autostart.xml";
+ var sCleanupPong = "fhir/StructureDefinition/dsf-task-cleanup-pong.xml";
+ var sNetworkSpeedExtension = "fhir/StructureDefinition/dsf-extension-network-speed.xml";
var tStartPing = "fhir/Task/dsf-task-start-ping.xml";
var tStartPingAutoStart = "fhir/Task/dsf-task-start-ping-autostart.xml";
var tStopPingAutoStart = "fhir/Task/dsf-task-stop-ping-autostart.xml";
var vPing = "fhir/ValueSet/dsf-ping.xml";
+ var vPingUnits = "fhir/ValueSet/dsf-ping-units.xml";
var vPingStatus = "fhir/ValueSet/dsf-ping-status.xml";
var vPongStatus = "fhir/ValueSet/dsf-pong-status.xml";
return Map.of(ConstantsPing.PROCESS_NAME_FULL_PING,
- Arrays.asList(
- aPing, cPing, cPingStatus, sPingStatus, sStartPing, sPong, tStartPing, vPing, vPingStatus),
+ Arrays.asList(aPing, cPing, cPingStatus, cPingUnits, sPingStatus, sStartPing, sPong, sCleanupPong,
+ sNetworkSpeedExtension, tStartPing, vPing, vPingStatus, vPingUnits),
ConstantsPing.PROCESS_NAME_FULL_PING_AUTOSTART,
Arrays.asList(aPingAutostart, cPing, sStartPingAutostart, sStopPingAutostart, tStartPingAutoStart,
tStopPingAutoStart, vPing),
- ConstantsPing.PROCESS_NAME_FULL_PONG,
- Arrays.asList(aPong, cPing, cPingStatus, sPingStatus, sPing, vPing, vPongStatus));
+ ConstantsPing.PROCESS_NAME_FULL_PONG, Arrays.asList(aPong, cPing, cPingStatus, cPingUnits, sPingStatus,
+ sPing, sNetworkSpeedExtension, vPing, vPongStatus, vPingUnits));
}
}
diff --git a/src/main/java/dev/dsf/bpe/listener/PingPongDeploymentStateListener.java b/src/main/java/dev/dsf/bpe/listener/PingPongDeploymentStateListener.java
new file mode 100644
index 00000000..6f6f4489
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/listener/PingPongDeploymentStateListener.java
@@ -0,0 +1,73 @@
+package dev.dsf.bpe.listener;
+
+import java.util.List;
+import java.util.Objects;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.InitializingBean;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.spring.config.PingConfig;
+import dev.dsf.bpe.v1.ProcessPluginDeploymentStateListener;
+
+public class PingPongDeploymentStateListener implements ProcessPluginDeploymentStateListener, InitializingBean
+{
+ private static final Logger logger = LoggerFactory.getLogger(PingPongDeploymentStateListener.class);
+
+ private final PingConfig pingConfig;
+ private final String networkSpeedUnit;
+
+ public PingPongDeploymentStateListener(PingConfig pingConfig)
+ {
+ this.pingConfig = pingConfig;
+ this.networkSpeedUnit = pingConfig.getNetworkSpeedUnit();
+ }
+
+ @Override
+ public void onProcessesDeployed(List processes)
+ {
+ logger.debug("Validating plugin configuration...");
+ if (ConstantsPing.CODESYSTEM_DSF_PING_UNITS_VALUES.contains(networkSpeedUnit))
+ {
+ logger.debug("Network speed unit is valid: {}", networkSpeedUnit);
+ }
+ else
+ {
+ pingConfig.setNetworkSpeedUnit(ConstantsPing.CODESYSTEM_DSF_PING_UNITS_VALUE_MEGABYTES_PER_SECOND);
+ logger.debug("Network speed unit \"{}\" is not valid. Valid values are: {}. Defaulting to \"{}\"",
+ networkSpeedUnit, ConstantsPing.CODESYSTEM_DSF_PING_UNITS_VALUES,
+ ConstantsPing.CODESYSTEM_DSF_PING_UNITS_VALUE_MEGABYTES_PER_SECOND);
+ }
+
+ // TODO: fixme
+ int maxDownloadSizeBytes = pingConfig.getMaxDownloadSizeBytes();
+ int maxDownloadSizeBytesHeapFix = 100000000;
+ if (maxDownloadSizeBytes > maxDownloadSizeBytesHeapFix)
+ {
+ pingConfig.setMaxDownloadSizeBytes(maxDownloadSizeBytesHeapFix);
+ logger.debug(
+ "MaxDownloadSizeBytes is too large. Setting maxDownloadSizeBytes to {}. This avoids Java running out of memory and will be fixed in a future release",
+ maxDownloadSizeBytesHeapFix);
+ }
+
+ int maxUploadSizeBytes = pingConfig.getMaxUploadSizeBytes();
+ int maxUploadSizeBytesHeapFix = 100000000;
+ if (maxUploadSizeBytes > maxUploadSizeBytesHeapFix)
+ {
+ pingConfig.setMaxUploadSizeBytes(maxUploadSizeBytesHeapFix);
+ logger.debug(
+ "MaxUploadSizeBytes is too large. Setting maxUploadSizeBytes to {}. This avoids Java running out of memory and will be fixed in a future release",
+ maxUploadSizeBytesHeapFix);
+ }
+
+ logger.debug("Configuration validation complete.");
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ Objects.requireNonNull(networkSpeedUnit);
+ Objects.requireNonNull(pingConfig);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/listener/SetCorrelationKeyListener.java b/src/main/java/dev/dsf/bpe/listener/SetCorrelationKeyListener.java
index 52089288..ec487ac1 100644
--- a/src/main/java/dev/dsf/bpe/listener/SetCorrelationKeyListener.java
+++ b/src/main/java/dev/dsf/bpe/listener/SetCorrelationKeyListener.java
@@ -6,6 +6,7 @@
import org.camunda.bpm.engine.delegate.ExecutionListener;
import org.springframework.beans.factory.InitializingBean;
+import dev.dsf.bpe.util.logging.PingPongLogger;
import dev.dsf.bpe.v1.ProcessPluginApi;
import dev.dsf.bpe.v1.constants.BpmnExecutionVariables;
import dev.dsf.bpe.v1.variables.Target;
@@ -29,6 +30,9 @@ public void afterPropertiesSet() throws Exception
@Override
public void notify(DelegateExecution execution) throws Exception
{
+ PingPongLogger logger = new PingPongLogger(SetCorrelationKeyListener.class,
+ api.getVariables(execution).getStartTask());
+ logger.debug("Setting correlation key for subprocess instance {}", execution.getProcessInstanceId());
Variables variables = api.getVariables(execution);
Target target = variables.getTarget();
diff --git a/src/main/java/dev/dsf/bpe/message/CleanupPong.java b/src/main/java/dev/dsf/bpe/message/CleanupPong.java
new file mode 100644
index 00000000..27eb0deb
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/message/CleanupPong.java
@@ -0,0 +1,80 @@
+package dev.dsf.bpe.message;
+
+import java.util.stream.Stream;
+
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.task.input.generator.DownloadedBytesGenerator;
+import dev.dsf.bpe.util.task.input.generator.DownloadedDurationMillisGenerator;
+import dev.dsf.bpe.util.task.input.generator.NetworkSpeedMetricGenerator;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractTaskMessageSend;
+import dev.dsf.bpe.v1.variables.Target;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class CleanupPong extends AbstractTaskMessageSend
+{
+ public CleanupPong(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected Stream getAdditionalInputParameters(DelegateExecution execution,
+ Variables variables)
+ {
+ Target target = variables.getTarget();
+ String correlationKey = target.getCorrelationKey();
+ Integer downloadedBytes = variables
+ .getInteger(ConstantsPing.getBpmnExecutionVariableDownloadedBytes(correlationKey));
+ Long downloadedDurationMillis = variables
+ .getLong(ConstantsPing.getBpmnExecutionVariableDownloadedDurationMillis(correlationKey));
+
+ Stream downloadedBytesParameter = downloadedBytes != null
+ ? Stream.of(DownloadedBytesGenerator.create(downloadedBytes))
+ : Stream.empty();
+ Stream downloadedDurationMillisParameter = downloadedDurationMillis != null
+ ? Stream.of(DownloadedDurationMillisGenerator.create(downloadedDurationMillis))
+ : Stream.empty();
+
+ return Stream.of(downloadedBytesParameter, downloadedDurationMillisParameter).flatMap(s -> s);
+ }
+
+ @Override
+ protected void sendTask(DelegateExecution execution, Variables variables, Target target,
+ String instantiatesCanonical, String messageName, String businessKey, String profile,
+ Stream additionalInputParameters)
+ {
+ Target newTarget = new Target()
+ {
+ @Override
+ public String getOrganizationIdentifierValue()
+ {
+ return target.getOrganizationIdentifierValue();
+ }
+
+ @Override
+ public String getEndpointIdentifierValue()
+ {
+ return target.getEndpointIdentifierValue();
+ }
+
+ @Override
+ public String getEndpointUrl()
+ {
+ return target.getEndpointUrl();
+ }
+
+ @Override
+ public String getCorrelationKey()
+ {
+ return null;
+ }
+ };
+
+ super.sendTask(execution, variables, newTarget, instantiatesCanonical, messageName, businessKey, profile,
+ additionalInputParameters);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/message/SendPing.java b/src/main/java/dev/dsf/bpe/message/SendPing.java
index 421fc176..1c9248b4 100644
--- a/src/main/java/dev/dsf/bpe/message/SendPing.java
+++ b/src/main/java/dev/dsf/bpe/message/SendPing.java
@@ -8,10 +8,15 @@
import org.hl7.fhir.r4.model.ResourceType;
import org.hl7.fhir.r4.model.Task;
import org.hl7.fhir.r4.model.Task.ParameterComponent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.task.input.generator.DownloadResourceReferenceGenerator;
+import dev.dsf.bpe.util.task.input.generator.DownloadResourceSizeGenerator;
import dev.dsf.bpe.v1.ProcessPluginApi;
import dev.dsf.bpe.v1.activity.AbstractTaskMessageSend;
+import dev.dsf.bpe.v1.variables.Target;
import dev.dsf.bpe.v1.variables.Variables;
import jakarta.ws.rs.WebApplicationException;
import jakarta.ws.rs.core.Response;
@@ -19,6 +24,8 @@
public class SendPing extends AbstractTaskMessageSend
{
+ private static final Logger logger = LoggerFactory.getLogger(SendPing.class);
+
public SendPing(ProcessPluginApi api)
{
super(api);
@@ -27,23 +34,38 @@ public SendPing(ProcessPluginApi api)
@Override
protected Stream getAdditionalInputParameters(DelegateExecution execution, Variables variables)
{
- return Stream.of(api.getTaskHelper().createInput(
+ String downloadResourceReference = variables
+ .getString(ConstantsPing.BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_REFERENCE);
+ int downloadResourceSizeBytes = variables
+ .getInteger(ConstantsPing.BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_SIZE_BYTES);
+
+ Stream downloadResourceReferenceStream = downloadResourceReference == null ? Stream.empty()
+ : Stream.of(DownloadResourceReferenceGenerator.create(downloadResourceReference));
+ Stream downloadResourceSizeBytesStream = Stream
+ .of(DownloadResourceSizeGenerator.create(downloadResourceSizeBytes));
+ Stream endpointIdentifierStream = Stream.of(api.getTaskHelper().createInput(
new Reference().setIdentifier(getLocalEndpointIdentifier()).setType(ResourceType.Endpoint.name()),
ConstantsPing.CODESYSTEM_DSF_PING, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_ENDPOINT_IDENTIFIER));
+
+ return Stream.concat(endpointIdentifierStream,
+ Stream.concat(downloadResourceReferenceStream, downloadResourceSizeBytesStream));
}
@Override
- protected void handleIntermediateThrowEventError(DelegateExecution execution, Variables variables,
- Exception exception, String errorMessage)
+ protected void handleSendTaskError(DelegateExecution execution, Variables variables, Exception exception,
+ String errorMessage)
{
+ Target target = variables.getTarget();
+
String statusCode = exception instanceof WebApplicationException w && w.getResponse() != null
&& w.getResponse().getStatus() == Response.Status.FORBIDDEN.getStatusCode()
? ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_ALLOWED
: ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_REACHABLE;
- execution.setVariableLocal("statusCode", statusCode);
+ execution.setVariableLocal(ConstantsPing.getBpmnExecutionVariableStatusCode(), statusCode);
String specialErrorMessage = createErrorMessage(exception);
- execution.setVariableLocal("errorMessage", specialErrorMessage);
+ execution.setVariableLocal(ConstantsPing.getBpmnExecutionVariableErrorMessage(), specialErrorMessage);
+ logger.info("Request to {} resulted in status {}", target.getEndpointUrl(), statusCode);
}
@Override
@@ -58,10 +80,11 @@ private String createErrorMessage(Exception exception)
&& (exception.getMessage() == null || exception.getMessage().isBlank()))
{
StatusType statusInfo = w.getResponse().getStatusInfo();
- return statusInfo.getStatusCode() + " " + statusInfo.getReasonPhrase();
+ return "Error when sending ping message: " + statusInfo.getStatusCode() + " "
+ + statusInfo.getReasonPhrase();
}
else
- return exception.getMessage();
+ return "Error when sending ping message: " + exception.getMessage();
}
private Identifier getLocalEndpointIdentifier()
diff --git a/src/main/java/dev/dsf/bpe/message/SendPong.java b/src/main/java/dev/dsf/bpe/message/SendPong.java
index 123a3441..0c738c35 100644
--- a/src/main/java/dev/dsf/bpe/message/SendPong.java
+++ b/src/main/java/dev/dsf/bpe/message/SendPong.java
@@ -1,13 +1,21 @@
package dev.dsf.bpe.message;
+import java.util.List;
import java.util.Objects;
+import java.util.stream.Stream;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.hl7.fhir.r4.model.Task;
import dev.dsf.bpe.ConstantsPing;
import dev.dsf.bpe.mail.ErrorMailService;
-import dev.dsf.bpe.util.PingStatusGenerator;
+import dev.dsf.bpe.util.ErrorMessageListUtils;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.util.task.input.generator.DownloadResourceReferenceGenerator;
+import dev.dsf.bpe.util.task.input.generator.DownloadedBytesGenerator;
+import dev.dsf.bpe.util.task.input.generator.DownloadedDurationMillisGenerator;
+import dev.dsf.bpe.util.task.input.generator.ErrorMessageGenerator;
+import dev.dsf.bpe.util.task.output.generator.PingStatusGenerator;
import dev.dsf.bpe.v1.ProcessPluginApi;
import dev.dsf.bpe.v1.activity.AbstractTaskMessageSend;
import dev.dsf.bpe.v1.variables.Target;
@@ -18,14 +26,12 @@
public class SendPong extends AbstractTaskMessageSend
{
- private final PingStatusGenerator statusGenerator;
private final ErrorMailService errorMailService;
- public SendPong(ProcessPluginApi api, PingStatusGenerator statusGenerator, ErrorMailService errorMailService)
+ public SendPong(ProcessPluginApi api, ErrorMailService errorMailService)
{
super(api);
- this.statusGenerator = statusGenerator;
this.errorMailService = errorMailService;
}
@@ -34,48 +40,77 @@ public void afterPropertiesSet() throws Exception
{
super.afterPropertiesSet();
- Objects.requireNonNull(statusGenerator, "statusGenerator");
Objects.requireNonNull(errorMailService, "errorMailService");
}
@Override
- protected void doExecute(DelegateExecution execution, Variables variables) throws Exception
+ protected Stream getAdditionalInputParameters(DelegateExecution execution,
+ Variables variables)
{
- super.doExecute(execution, variables);
+ List errorList = ErrorMessageListUtils.getErrorMessageList(execution);
+ int downloadResourceSizeBytes = variables
+ .getInteger(ConstantsPing.BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_SIZE_BYTES);
+ if (downloadResourceSizeBytes >= 0)
+ {
+ Integer downloadedBytes = variables.getInteger(ConstantsPing.getBpmnExecutionVariableDownloadedBytes());
+ Long downloadedDurationMillis = variables
+ .getLong(ConstantsPing.getBpmnExecutionVariableDownloadedDurationMillis());
+ String downloadResourceReference = variables
+ .getString(ConstantsPing.BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_REFERENCE);
+
+ Stream downloadedBytesParameter = downloadedBytes != null
+ ? Stream.of(DownloadedBytesGenerator.create(downloadedBytes))
+ : Stream.empty();
+ Stream downloadedDurationMillisParameter = downloadedDurationMillis != null
+ ? Stream.of(DownloadedDurationMillisGenerator.create(downloadedDurationMillis))
+ : Stream.empty();
+ Stream downloadedResourceReferenceParameter = downloadResourceReference != null
+ ? Stream.of(DownloadResourceReferenceGenerator.create(downloadResourceReference))
+ : Stream.empty();
+
+ return Stream
+ .of(downloadedBytesParameter, downloadedDurationMillisParameter,
+ downloadedResourceReferenceParameter, ErrorMessageGenerator.create(errorList).stream())
+ .flatMap(stream -> stream);
+ }
+ else
+ {
+ return ErrorMessageGenerator.create(errorList).stream();
+ }
+ }
+ @Override
+ protected void doExecute(DelegateExecution execution, Variables variables) throws Exception
+ {
Target target = variables.getTarget();
Task mainTask = variables.getStartTask();
- mainTask.addOutput(statusGenerator.createPongStatusOutput(target,
- ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_SEND));
+ PingStatusGenerator.updatePongStatusOutput(mainTask, target);
+ PingStatusGenerator.updatePongStatusOutput(mainTask, ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_SENT);
variables.updateTask(mainTask);
+ super.doExecute(execution, variables);
}
@Override
- protected void handleEndEventError(DelegateExecution execution, Variables variables, Exception exception,
+ protected void handleSendTaskError(DelegateExecution execution, Variables variables, Exception exception,
String errorMessage)
{
+ PingPongLogger logger = new PingPongLogger(SendPong.class, variables.getStartTask());
Target target = variables.getTarget();
- Task mainTask = variables.getStartTask();
+ Task startTask = variables.getStartTask();
- if (mainTask != null)
- {
- String statusCode = exception instanceof WebApplicationException w && w.getResponse() != null
- && w.getResponse().getStatus() == Response.Status.FORBIDDEN.getStatusCode()
- ? ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_ALLOWED
- : ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_REACHABLE;
-
- String specialErrorMessage = createErrorMessage(exception);
+ String statusCode = exception instanceof WebApplicationException w && w.getResponse() != null
+ && w.getResponse().getStatus() == Response.Status.FORBIDDEN.getStatusCode()
+ ? ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_ALLOWED
+ : ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_REACHABLE;
+ execution.setVariable(ConstantsPing.getBpmnExecutionVariableStatusCode(), statusCode);
- mainTask.addOutput(statusGenerator.createPongStatusOutput(target, statusCode, specialErrorMessage));
- variables.updateTask(mainTask);
-
- if (ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_REACHABLE.equals(statusCode))
- errorMailService.endpointNotReachableForPong(mainTask.getIdElement(), target, specialErrorMessage);
- else if (ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_ALLOWED.equals(statusCode))
- errorMailService.endpointReachablePongForbidden(mainTask.getIdElement(), target, specialErrorMessage);
- }
+ String specialErrorMessage = createErrorMessage(exception);
+ ErrorMessageListUtils.add(specialErrorMessage, execution);
+ PingStatusGenerator.updatePongStatusOutput(startTask, statusCode);
+ variables.setString(ConstantsPing.getBpmnExecutionVariableStatusCode(), statusCode);
- super.handleEndEventError(execution, variables, exception, errorMessage);
+ logger.info("Request to {} resulted in status {}", target.getEndpointUrl(), statusCode);
+ variables.updateTask(startTask);
}
private String createErrorMessage(Exception exception)
@@ -84,9 +119,10 @@ private String createErrorMessage(Exception exception)
&& (exception.getMessage() == null || exception.getMessage().isBlank()))
{
StatusType statusInfo = w.getResponse().getStatusInfo();
- return statusInfo.getStatusCode() + " " + statusInfo.getReasonPhrase();
+ return "Error when sending pong message: " + statusInfo.getStatusCode() + " "
+ + statusInfo.getReasonPhrase();
}
else
- return exception.getMessage();
+ return "Error when sending ping message: " + exception.getMessage();
}
}
diff --git a/src/main/java/dev/dsf/bpe/message/SendStartPing.java b/src/main/java/dev/dsf/bpe/message/SendStartPing.java
index 196d828b..c7cdeadc 100644
--- a/src/main/java/dev/dsf/bpe/message/SendStartPing.java
+++ b/src/main/java/dev/dsf/bpe/message/SendStartPing.java
@@ -1,5 +1,6 @@
package dev.dsf.bpe.message;
+import java.util.UUID;
import java.util.stream.Stream;
import org.camunda.bpm.engine.delegate.DelegateExecution;
@@ -9,6 +10,7 @@
import dev.dsf.bpe.ConstantsPing;
import dev.dsf.bpe.v1.ProcessPluginApi;
import dev.dsf.bpe.v1.activity.AbstractTaskMessageSend;
+import dev.dsf.bpe.v1.variables.Target;
import dev.dsf.bpe.v1.variables.Variables;
public class SendStartPing extends AbstractTaskMessageSend
@@ -21,9 +23,36 @@ public SendStartPing(ProcessPluginApi api)
@Override
protected Stream getAdditionalInputParameters(DelegateExecution execution, Variables variables)
{
- return variables.getStartTask().getInput().stream().filter(Task.ParameterComponent::hasType)
- .filter(i -> i.getType().getCoding().stream()
+ return Stream.concat(
+ variables.getStartTask().getInput().stream().filter(Task.ParameterComponent::hasType).filter(i -> i
+ .getType().getCoding().stream()
.anyMatch(c -> ConstantsPing.CODESYSTEM_DSF_PING.equals(c.getSystem())
- && ConstantsPing.CODESYSTEM_DSF_PING_VALUE_TARGET_ENDPOINTS.equals(c.getCode())));
+ && ConstantsPing.CODESYSTEM_DSF_PING_VALUE_TARGET_ENDPOINTS.equals(c.getCode()))),
+ Stream.of(getDownloadResourceSizeInputParameter(variables)));
+ }
+
+ private ParameterComponent getDownloadResourceSizeInputParameter(Variables variables)
+ {
+ return variables.getStartTask().getInput().stream().filter(this::isDownloadResourceSizeParameter).findFirst()
+ .orElseThrow();
+ }
+
+ private boolean isDownloadResourceSizeParameter(ParameterComponent parameterComponent)
+ {
+ return parameterComponent.getType().getCoding().stream()
+ .anyMatch(t -> ConstantsPing.CODESYSTEM_DSF_PING.equals(t.getSystem())
+ && ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOAD_RESOURCE_SIZE_BYTES.equals(t.getCode()));
+ }
+
+ @Override
+ protected void sendTask(DelegateExecution execution, Variables variables, Target target,
+ String instantiatesCanonical, String messageName, String businessKey, String profile,
+ Stream additionalInputParameters)
+ {
+ // different business-key for every start-ping execution
+ businessKey = UUID.randomUUID().toString();
+
+ super.sendTask(execution, variables, target, instantiatesCanonical, messageName, businessKey, profile,
+ additionalInputParameters);
}
}
diff --git a/src/main/java/dev/dsf/bpe/service/Cleanup.java b/src/main/java/dev/dsf/bpe/service/Cleanup.java
new file mode 100644
index 00000000..064632a0
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/Cleanup.java
@@ -0,0 +1,41 @@
+package dev.dsf.bpe.service;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.Binary;
+import org.hl7.fhir.r4.model.IdType;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class Cleanup extends AbstractServiceDelegate
+{
+ public Cleanup(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(Cleanup.class, variables.getStartTask());
+ logger.debug("Cleaning up...");
+ String downloadResourceId = new IdType(
+ variables.getString(ConstantsPing.BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_REFERENCE)).getIdPart();
+ if (downloadResourceId != null)
+ {
+ api.getFhirWebserviceClientProvider().getLocalWebserviceClient().delete(Binary.class, downloadResourceId);
+ api.getFhirWebserviceClientProvider().getLocalWebserviceClient().deletePermanently(Binary.class,
+ downloadResourceId);
+ logger.debug("Deleted Binary resource with ID {}", downloadResourceId);
+ }
+ else
+ {
+ logger.debug("Nothing to do");
+ }
+ logger.debug("Cleanup complete.");
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/GenerateAndStoreResource.java b/src/main/java/dev/dsf/bpe/service/GenerateAndStoreResource.java
new file mode 100644
index 00000000..d842d60f
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/GenerateAndStoreResource.java
@@ -0,0 +1,85 @@
+package dev.dsf.bpe.service;
+
+import java.io.ByteArrayInputStream;
+import java.util.Random;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.IdType;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+import jakarta.ws.rs.WebApplicationException;
+
+public class GenerateAndStoreResource extends AbstractServiceDelegate
+{
+ private final int maxUploadSizeBytes;
+
+ public GenerateAndStoreResource(ProcessPluginApi api, int maxUploadSizeBytes)
+ {
+ super(api);
+ this.maxUploadSizeBytes = maxUploadSizeBytes;
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(GenerateAndStoreResource.class, variables.getStartTask());
+ logger.debug("Generating resource...");
+ int downloadResourceSizeBytes = getDownloadResourceSize(variables);
+
+ byte[] resourceContent = generateRandomBinaryContent(downloadResourceSizeBytes, logger);
+ variables.setInteger(ConstantsPing.BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_SIZE_BYTES,
+ resourceContent.length);
+ logger.debug("Generated resource.");
+ logger.debug("Storing binary resource for download...");
+
+ try
+ {
+ IdType downloadResource = storeBinary(resourceContent);
+
+ String reference = downloadResource.getValueAsString();
+
+ variables.setString(ConstantsPing.BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_REFERENCE, reference);
+
+ logger.debug("Stored binary resource for download");
+ }
+ catch (Exception e)
+ {
+ throw new BpmnError(ConstantsPing.BPMN_ERROR_CODE_RESOURCE_UPLOAD_ERROR, e.getMessage());
+ }
+ }
+
+ private byte[] generateRandomBinaryContent(int desiredSizeBytes, PingPongLogger logger)
+ {
+ int sizeBytes = Math.min(maxUploadSizeBytes, desiredSizeBytes);
+ byte[] bytes = generateRandomByteArray(sizeBytes);
+ logger.info(
+ "Generated binary content for network speed measurement. Requested size was: {} bytes, generated size was : {}",
+ desiredSizeBytes, bytes.length);
+ return bytes;
+ }
+
+ private byte[] generateRandomByteArray(int sizeBytes)
+ {
+ Random rand = new Random();
+ byte[] randomBytes = new byte[sizeBytes];
+ rand.nextBytes(randomBytes);
+ return randomBytes;
+ }
+
+ private int getDownloadResourceSize(Variables variables)
+ {
+ return variables.getInteger(ConstantsPing.BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_SIZE_BYTES);
+ }
+
+ private IdType storeBinary(byte[] downloadResourceContent)
+ {
+ return api.getFhirWebserviceClientProvider().getLocalWebserviceClient().withMinimalReturn().createBinary(
+ new ByteArrayInputStream(downloadResourceContent), ConstantsPing.DOWNLOAD_RESOURCE_MIME_TYPE,
+ api.getOrganizationProvider().getLocalOrganization().get().getIdElement().getValue());
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/LogNoResponse.java b/src/main/java/dev/dsf/bpe/service/LogNoResponse.java
deleted file mode 100644
index b8ec0cc3..00000000
--- a/src/main/java/dev/dsf/bpe/service/LogNoResponse.java
+++ /dev/null
@@ -1,34 +0,0 @@
-package dev.dsf.bpe.service;
-
-import org.camunda.bpm.engine.delegate.BpmnError;
-import org.camunda.bpm.engine.delegate.DelegateExecution;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import dev.dsf.bpe.ConstantsPing;
-import dev.dsf.bpe.v1.ProcessPluginApi;
-import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
-import dev.dsf.bpe.v1.variables.Target;
-import dev.dsf.bpe.v1.variables.Variables;
-
-public class LogNoResponse extends AbstractServiceDelegate
-{
- private static final Logger logger = LoggerFactory.getLogger(LogNoResponse.class);
-
- public LogNoResponse(ProcessPluginApi api)
- {
- super(api);
- }
-
- @Override
- protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
- {
- Target target = variables.getTarget();
-
- logger.warn("PONG from organization {} (endpoint {}) missing", target.getOrganizationIdentifierValue(),
- target.getEndpointIdentifierValue());
-
- variables.setString("statusCode_" + target.getCorrelationKey(),
- ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_MISSING);
- }
-}
diff --git a/src/main/java/dev/dsf/bpe/service/LogPong.java b/src/main/java/dev/dsf/bpe/service/LogPong.java
deleted file mode 100644
index 72fa6168..00000000
--- a/src/main/java/dev/dsf/bpe/service/LogPong.java
+++ /dev/null
@@ -1,36 +0,0 @@
-package dev.dsf.bpe.service;
-
-import org.camunda.bpm.engine.delegate.BpmnError;
-import org.camunda.bpm.engine.delegate.DelegateExecution;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import dev.dsf.bpe.ConstantsPing;
-import dev.dsf.bpe.v1.ProcessPluginApi;
-import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
-import dev.dsf.bpe.v1.variables.Target;
-import dev.dsf.bpe.v1.variables.Variables;
-
-public class LogPong extends AbstractServiceDelegate
-{
- private static final Logger logger = LoggerFactory.getLogger(LogPong.class);
-
- public LogPong(ProcessPluginApi api)
- {
- super(api);
-
- }
-
- @Override
- protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
- {
- Target target = variables.getTarget();
-
- logger.info("PONG from {} (endpoint: {})", target.getOrganizationIdentifierValue(),
- target.getEndpointIdentifierValue());
-
- execution.removeVariable("statusCode");
- variables.setString("statusCode_" + target.getCorrelationKey(),
- ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_RECEIVED);
- }
-}
diff --git a/src/main/java/dev/dsf/bpe/service/LogSendError.java b/src/main/java/dev/dsf/bpe/service/LogSendError.java
deleted file mode 100644
index ed06bfcc..00000000
--- a/src/main/java/dev/dsf/bpe/service/LogSendError.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package dev.dsf.bpe.service;
-
-import org.camunda.bpm.engine.delegate.BpmnError;
-import org.camunda.bpm.engine.delegate.DelegateExecution;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import dev.dsf.bpe.v1.ProcessPluginApi;
-import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
-import dev.dsf.bpe.v1.variables.Target;
-import dev.dsf.bpe.v1.variables.Variables;
-
-public class LogSendError extends AbstractServiceDelegate
-{
- private static final Logger logger = LoggerFactory.getLogger(LogSendError.class);
-
- public LogSendError(ProcessPluginApi api)
- {
- super(api);
- }
-
- @Override
- protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
- {
- Target target = variables.getTarget();
- String statusCode = (String) execution.getVariableLocal("statusCode");
- String errorMessage = (String) execution.getVariableLocal("errorMessage");
-
- logger.warn("Unable to send PING to {} (endpoint: {}): {}", target.getOrganizationIdentifierValue(),
- target.getEndpointIdentifierValue(), errorMessage);
-
- variables.setString("statusCode_" + target.getCorrelationKey(), statusCode);
- variables.setString("errorMessage_" + target.getCorrelationKey(), errorMessage);
- }
-}
diff --git a/src/main/java/dev/dsf/bpe/service/SaveResults.java b/src/main/java/dev/dsf/bpe/service/SaveResults.java
deleted file mode 100644
index 1edc5575..00000000
--- a/src/main/java/dev/dsf/bpe/service/SaveResults.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package dev.dsf.bpe.service;
-
-import java.util.Comparator;
-import java.util.Objects;
-
-import org.camunda.bpm.engine.delegate.BpmnError;
-import org.camunda.bpm.engine.delegate.DelegateExecution;
-import org.hl7.fhir.r4.model.Task;
-import org.springframework.beans.factory.InitializingBean;
-
-import dev.dsf.bpe.ConstantsPing;
-import dev.dsf.bpe.mail.ErrorMailService;
-import dev.dsf.bpe.util.PingStatusGenerator;
-import dev.dsf.bpe.v1.ProcessPluginApi;
-import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
-import dev.dsf.bpe.v1.variables.Target;
-import dev.dsf.bpe.v1.variables.Targets;
-import dev.dsf.bpe.v1.variables.Variables;
-
-public class SaveResults extends AbstractServiceDelegate implements InitializingBean
-{
- private final PingStatusGenerator statusGenerator;
- private final ErrorMailService errorMailService;
-
- public SaveResults(ProcessPluginApi api, PingStatusGenerator statusGenerator, ErrorMailService errorMailService)
- {
- super(api);
-
- this.statusGenerator = statusGenerator;
- this.errorMailService = errorMailService;
- }
-
- @Override
- public void afterPropertiesSet() throws Exception
- {
- super.afterPropertiesSet();
-
- Objects.requireNonNull(statusGenerator, "statusGenerator");
- Objects.requireNonNull(errorMailService, "errorMailService");
- }
-
- @Override
- protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
- {
- Task task = variables.getStartTask();
- Targets targets = variables.getTargets();
-
- targets.getEntries().stream().sorted(Comparator.comparing(Target::getEndpointIdentifierValue)).forEach(target ->
- {
- String correlationKey = target.getCorrelationKey();
-
- String statusCode = variables.getString("statusCode_" + correlationKey);
- if (ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_REACHABLE.equals(statusCode)
- || ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_ALLOWED.equals(statusCode))
- {
- String errorMessage = variables.getString("errorMessage_" + correlationKey);
- task.addOutput(statusGenerator.createPingStatusOutput(target, statusCode, errorMessage));
-
- if (ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_REACHABLE.equals(statusCode))
- errorMailService.endpointNotReachableForPing(task.getIdElement(), target, errorMessage);
- else if (ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_ALLOWED.equals(statusCode))
- errorMailService.endpointReachablePingForbidden(task.getIdElement(), target, errorMessage);
- }
- else
- {
- task.addOutput(statusGenerator.createPingStatusOutput(target, statusCode));
-
- if (ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_MISSING.equals(statusCode))
- errorMailService.pongMessageNotReceived(task.getIdElement(), target);
- }
- });
-
- // TODO only send one combined status mail
-
- variables.updateTask(task);
- }
-}
diff --git a/src/main/java/dev/dsf/bpe/service/SetDownloadResourceSize.java b/src/main/java/dev/dsf/bpe/service/SetDownloadResourceSize.java
new file mode 100644
index 00000000..31e5d7c1
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/SetDownloadResourceSize.java
@@ -0,0 +1,46 @@
+package dev.dsf.bpe.service;
+
+import java.util.Optional;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.IntegerType;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class SetDownloadResourceSize extends AbstractServiceDelegate
+{
+ private final int maxDownloadResourceSizeBytes;
+
+ public SetDownloadResourceSize(ProcessPluginApi api, int maxDownloadResourceSizeBytes)
+ {
+ super(api);
+ this.maxDownloadResourceSizeBytes = maxDownloadResourceSizeBytes;
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(SetDownloadResourceSize.class, variables.getStartTask());
+ logger.debug("Setting download resource size...");
+
+ variables.setInteger(ConstantsPing.BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_SIZE_BYTES,
+ getDownloadResourceSize(variables));
+
+ logger.debug("Set download resource size to " + maxDownloadResourceSizeBytes);
+ }
+
+ private int getDownloadResourceSize(Variables variables)
+ {
+ Optional downloadResourceSizeType = api.getTaskHelper().getFirstInputParameterValue(
+ variables.getStartTask(), ConstantsPing.CODESYSTEM_DSF_PING,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOAD_RESOURCE_SIZE_BYTES, IntegerType.class);
+
+ return downloadResourceSizeType.isPresent() ? downloadResourceSizeType.get().getValue()
+ : Math.min(maxDownloadResourceSizeBytes, ConstantsPing.DOWNLOAD_RESOURCE_SIZE_BYTES_DEFAULT);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/SetTargetAndConfigureTimer.java b/src/main/java/dev/dsf/bpe/service/autostart/SetTargetAndConfigureTimer.java
similarity index 97%
rename from src/main/java/dev/dsf/bpe/service/SetTargetAndConfigureTimer.java
rename to src/main/java/dev/dsf/bpe/service/autostart/SetTargetAndConfigureTimer.java
index 4df0f1a4..a594a7e1 100644
--- a/src/main/java/dev/dsf/bpe/service/SetTargetAndConfigureTimer.java
+++ b/src/main/java/dev/dsf/bpe/service/autostart/SetTargetAndConfigureTimer.java
@@ -1,4 +1,4 @@
-package dev.dsf.bpe.service;
+package dev.dsf.bpe.service.autostart;
import org.camunda.bpm.engine.delegate.BpmnError;
import org.camunda.bpm.engine.delegate.DelegateExecution;
diff --git a/src/main/java/dev/dsf/bpe/service/ping/DownloadResourceAndMeasureSpeedInSubProcess.java b/src/main/java/dev/dsf/bpe/service/ping/DownloadResourceAndMeasureSpeedInSubProcess.java
new file mode 100644
index 00000000..6538c8e3
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/ping/DownloadResourceAndMeasureSpeedInSubProcess.java
@@ -0,0 +1,61 @@
+package dev.dsf.bpe.service.ping;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.BinaryResourceDownloader;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Target;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class DownloadResourceAndMeasureSpeedInSubProcess extends AbstractServiceDelegate
+{
+ private final int maxDownloadSizeBytes;
+
+ public DownloadResourceAndMeasureSpeedInSubProcess(ProcessPluginApi api, int maxDownloadSizeBytes)
+ {
+ super(api);
+ this.maxDownloadSizeBytes = maxDownloadSizeBytes;
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(DownloadResourceAndMeasureSpeedInSubProcess.class,
+ variables.getStartTask());
+ logger.debug("Starting resource download to measure speed...");
+
+ Task task = variables.getLatestTask();
+ Target target = variables.getTarget();
+ String correlationKey = target.getCorrelationKey();
+
+ try
+ {
+ BinaryResourceDownloader.DownloadResult downloadResult = new BinaryResourceDownloader(logger)
+ .download(variables, api, task, maxDownloadSizeBytes);
+
+ if (downloadResult.getErrorMessage() == null)
+ {
+ variables.setInteger(ConstantsPing.getBpmnExecutionVariableDownloadedBytes(correlationKey),
+ downloadResult.getDownloadedBytes());
+ variables.setLong(ConstantsPing.getBpmnExecutionVariableDownloadedDurationMillis(correlationKey),
+ downloadResult.getDownloadedDurationMillis());
+ }
+ else
+ {
+ throw new BpmnError(ConstantsPing.BPMN_ERROR_CODE_RESOURCE_DOWNLOAD_ERROR,
+ downloadResult.getErrorMessage());
+ }
+
+ logger.debug("Completed resource download and measured speed.");
+ }
+ catch (Exception e)
+ {
+ throw new BpmnError(ConstantsPing.BPMN_ERROR_CODE_RESOURCE_DOWNLOAD_ERROR, e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/ping/LogAndSaveError.java b/src/main/java/dev/dsf/bpe/service/ping/LogAndSaveError.java
new file mode 100644
index 00000000..77cd38b0
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/ping/LogAndSaveError.java
@@ -0,0 +1,33 @@
+package dev.dsf.bpe.service.ping;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.ErrorMessageListUtils;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Target;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class LogAndSaveError extends AbstractServiceDelegate
+{
+ public LogAndSaveError(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(LogAndSaveError.class, variables.getStartTask());
+ Target target = variables.getTarget();
+
+ String errorMessage = variables
+ .getString(ConstantsPing.BPMN_EXECUTION_VARIABLE_RESOURCE_DOWNLOAD_ERROR_MESSAGE);
+ ErrorMessageListUtils.add(errorMessage, delegateExecution, target.getCorrelationKey());
+
+ logger.info("Error while trying to download resource from {}: {}", target.getEndpointUrl(), errorMessage);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/ping/LogAndSaveNoResponse.java b/src/main/java/dev/dsf/bpe/service/ping/LogAndSaveNoResponse.java
new file mode 100644
index 00000000..28f6c6f1
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/ping/LogAndSaveNoResponse.java
@@ -0,0 +1,37 @@
+package dev.dsf.bpe.service.ping;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Target;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class LogAndSaveNoResponse extends AbstractServiceDelegate
+{
+ public LogAndSaveNoResponse(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(LogAndSaveNoResponse.class, variables.getStartTask());
+ logger.debug("Saving no response to process execution...");
+
+ Target target = variables.getTarget();
+ logger.info("No PONG received from endpoint '{}'", target.getEndpointIdentifierValue());
+
+ String correlationKey = target.getCorrelationKey();
+ delegateExecution.removeVariable("statusCode");
+ variables.setString(ConstantsPing.getBpmnExecutionVariableStatusCode(correlationKey),
+ ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_MISSING);
+
+ logger.debug("Saved '{}' to process execution for correlation key '{}'",
+ ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_MISSING, correlationKey);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/ping/LogAndSaveSendError.java b/src/main/java/dev/dsf/bpe/service/ping/LogAndSaveSendError.java
new file mode 100644
index 00000000..11e7ec12
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/ping/LogAndSaveSendError.java
@@ -0,0 +1,36 @@
+package dev.dsf.bpe.service.ping;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.ErrorMessageListUtils;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class LogAndSaveSendError extends AbstractServiceDelegate
+{
+ public LogAndSaveSendError(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(LogAndSaveSendError.class, variables.getStartTask());
+
+ String correlationKey = variables.getTarget().getCorrelationKey();
+ String statusCode = (String) execution.getVariableLocal(ConstantsPing.getBpmnExecutionVariableStatusCode());
+ String errorMessage = (String) execution.getVariableLocal(ConstantsPing.getBpmnExecutionVariableErrorMessage());
+
+ variables.setString(ConstantsPing.getBpmnExecutionVariableStatusCode(correlationKey), statusCode);
+ ErrorMessageListUtils.add(errorMessage, execution, correlationKey);
+ variables.setInteger(ConstantsPing.getBpmnExecutionVariableUploadedBytes(correlationKey), 0);
+ variables.setLong(ConstantsPing.getBpmnExecutionVariableDownloadedDurationMillis(correlationKey), 0L);
+ logger.debug("Saved error when trying to send ping message. Status: {}, error message: {}", statusCode,
+ errorMessage);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/ping/LogAndSaveUploadErrorPing.java b/src/main/java/dev/dsf/bpe/service/ping/LogAndSaveUploadErrorPing.java
new file mode 100644
index 00000000..c1600bc4
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/ping/LogAndSaveUploadErrorPing.java
@@ -0,0 +1,32 @@
+package dev.dsf.bpe.service.ping;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.ErrorMessageListUtils;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class LogAndSaveUploadErrorPing extends AbstractServiceDelegate
+{
+ public LogAndSaveUploadErrorPing(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
+ {
+ Task startTask = variables.getStartTask();
+ PingPongLogger logger = new PingPongLogger(LogAndSaveUploadErrorPing.class, startTask);
+
+ String errorMessage = variables.getString(ConstantsPing.BPMN_EXECUTION_VARIABLE_RESOURCE_UPLOAD_ERROR_MESSAGE);
+ ErrorMessageListUtils.add(errorMessage, execution);
+
+ logger.info("Error while storing binary resource for download: {}", errorMessage);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/ping/SavePong.java b/src/main/java/dev/dsf/bpe/service/ping/SavePong.java
new file mode 100644
index 00000000..6528c336
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/ping/SavePong.java
@@ -0,0 +1,66 @@
+package dev.dsf.bpe.service.ping;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.DecimalType;
+import org.hl7.fhir.r4.model.IntegerType;
+import org.hl7.fhir.r4.model.PrimitiveType;
+import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.ErrorMessageListUtils;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Target;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class SavePong extends AbstractServiceDelegate
+{
+ public SavePong(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(SavePong.class, variables.getStartTask());
+
+ Target target = variables.getTarget();
+ logger.debug("Pong received from {}. Saving pong information...", target.getEndpointUrl());
+ String correlationKey = target.getCorrelationKey();
+ delegateExecution.removeVariable("statusCode");
+ variables.setString(ConstantsPing.getBpmnExecutionVariableStatusCode(correlationKey),
+ ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_RECEIVED);
+
+ Task pong = variables.getLatestTask();
+
+ Optional optDownloadedDurationMillis = api.getTaskHelper().getFirstInputParameterValue(pong,
+ ConstantsPing.CODESYSTEM_DSF_PING, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOADED_DURATION_MILLIS,
+ DecimalType.class);
+ optDownloadedDurationMillis.ifPresent(decimalType -> variables.setLong(
+ ConstantsPing.getBpmnExecutionVariableUploadedDurationMillis(correlationKey),
+ decimalType.getValue().longValue()));
+
+ Optional optDownloadedBytes = api.getTaskHelper().getFirstInputParameterValue(pong,
+ ConstantsPing.CODESYSTEM_DSF_PING, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOADED_BYTES,
+ IntegerType.class);
+ optDownloadedBytes.ifPresent(integerType -> variables.setInteger(
+ ConstantsPing.getBpmnExecutionVariableUploadedBytes(correlationKey), integerType.getValue()));
+
+
+ List errorList = api.getTaskHelper()
+ .getInputParameterValues(pong, ConstantsPing.CODESYSTEM_DSF_PING,
+ ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_ERROR_MESSAGE, StringType.class)
+ .map(PrimitiveType::getValue).map(string -> "Pong error: " + string).toList();
+
+ ErrorMessageListUtils.addAll(errorList, delegateExecution, correlationKey);
+
+ logger.debug("Saved pong information.");
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/SelectPingTargets.java b/src/main/java/dev/dsf/bpe/service/ping/SelectPingTargets.java
similarity index 89%
rename from src/main/java/dev/dsf/bpe/service/SelectPingTargets.java
rename to src/main/java/dev/dsf/bpe/service/ping/SelectPingTargets.java
index ff52d009..28563877 100644
--- a/src/main/java/dev/dsf/bpe/service/SelectPingTargets.java
+++ b/src/main/java/dev/dsf/bpe/service/ping/SelectPingTargets.java
@@ -1,4 +1,4 @@
-package dev.dsf.bpe.service;
+package dev.dsf.bpe.service.ping;
import java.util.Collections;
import java.util.HashMap;
@@ -22,13 +22,12 @@
import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.logging.PingPongLogger;
import dev.dsf.bpe.v1.ProcessPluginApi;
import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
import dev.dsf.bpe.v1.constants.NamingSystems.EndpointIdentifier;
@@ -38,7 +37,6 @@
public class SelectPingTargets extends AbstractServiceDelegate implements InitializingBean
{
- private static final Logger logger = LoggerFactory.getLogger(SelectPingTargets.class);
private static final Pattern endpointResouceTypes = Pattern.compile(
"Endpoint|HealthcareService|ImagingStudy|InsurancePlan|Location|Organization|OrganizationAffiliation|PractitionerRole");
@@ -51,8 +49,10 @@ public SelectPingTargets(ProcessPluginApi api)
@Override
protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
{
- Stream targetEndpoints = getTargetEndpointsSearchParameter(variables).map(this::searchForEndpoints)
- .orElse(allEndpoints()).filter(isLocalEndpoint().negate());
+ Task startTask = variables.getStartTask();
+ Stream targetEndpoints = getTargetEndpointsSearchParameter(variables)
+ .map(uriComponents -> searchForEndpoints(uriComponents, startTask)).orElse(allEndpoints())
+ .filter(isLocalEndpoint().negate());
List remoteOrganizations = api.getOrganizationProvider().getRemoteOrganizations();
Map organizationIdentifierByOrganizationId = remoteOrganizations.stream().collect(
@@ -83,17 +83,18 @@ private Optional getTargetEndpointsSearchParameter(Variables vari
.map(requestUrl -> UriComponentsBuilder.fromUriString(requestUrl).build());
}
- private Stream searchForEndpoints(UriComponents searchParameters)
+ private Stream searchForEndpoints(UriComponents searchParameters, Task startTask)
{
- return searchForEndpoints(searchParameters, 1, 0);
+ return searchForEndpoints(searchParameters, 1, 0, startTask);
}
- private Stream searchForEndpoints(UriComponents searchParameters, int page, int currentTotal)
+ private Stream searchForEndpoints(UriComponents searchParameters, int page, int currentTotal,
+ Task startTask)
{
if (searchParameters.getPathSegments().isEmpty())
return Stream.empty();
- Optional> resourceType = getResourceType(searchParameters);
+ Optional> resourceType = getResourceType(searchParameters, startTask);
if (resourceType.isEmpty())
return Stream.empty();
@@ -105,14 +106,14 @@ private Stream searchForEndpoints(UriComponents searchParameters, int
.searchWithStrictHandling(resourceType.get(), queryParameters);
if (searchResult.getTotal() > currentTotal + searchResult.getEntry().size())
- return Stream.concat(toEndpoints(searchResult),
- searchForEndpoints(searchParameters, page + 1, currentTotal + searchResult.getEntry().size()));
+ return Stream.concat(toEndpoints(searchResult), searchForEndpoints(searchParameters, page + 1,
+ currentTotal + searchResult.getEntry().size(), startTask));
else
return toEndpoints(searchResult);
}
@SuppressWarnings("unchecked")
- private Optional> getResourceType(UriComponents searchParameters)
+ private Optional> getResourceType(UriComponents searchParameters, Task startTask)
{
if (searchParameters.getPathSegments().isEmpty())
return Optional.empty();
@@ -127,6 +128,7 @@ private Optional> getResourceType(UriComponents search
}
catch (ClassNotFoundException e)
{
+ PingPongLogger logger = new PingPongLogger(SelectPingTargets.class, startTask);
logger.error("Unable to find class for FHIR resource type " + type, e);
return Optional.empty();
}
diff --git a/src/main/java/dev/dsf/bpe/service/ping/StoreResults.java b/src/main/java/dev/dsf/bpe/service/ping/StoreResults.java
new file mode 100644
index 00000000..f79860a3
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/ping/StoreResults.java
@@ -0,0 +1,124 @@
+package dev.dsf.bpe.service.ping;
+
+import java.math.BigDecimal;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.Task;
+import org.springframework.beans.factory.InitializingBean;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.mail.ErrorMailService;
+import dev.dsf.bpe.util.ErrorMessageListUtils;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.util.task.NetworkSpeedCalculator;
+import dev.dsf.bpe.util.task.output.generator.ErrorMessageGenerator;
+import dev.dsf.bpe.util.task.output.generator.PingStatusGenerator;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Target;
+import dev.dsf.bpe.v1.variables.Targets;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class StoreResults extends AbstractServiceDelegate implements InitializingBean
+{
+ private final ErrorMailService errorMailService;
+ private final String networkSpeedUnit;
+
+ public StoreResults(ProcessPluginApi api, ErrorMailService errorMailService, String networkSpeedUnit)
+ {
+ super(api);
+ this.networkSpeedUnit = networkSpeedUnit;
+ this.errorMailService = errorMailService;
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception
+ {
+ super.afterPropertiesSet();
+
+ Objects.requireNonNull(errorMailService, "errorMailService");
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(StoreResults.class, variables.getStartTask());
+
+ logger.debug("Storing results for process started with Task {}",
+ variables.getStartTask().getIdElement().getValue());
+ Task task = variables.getStartTask();
+ Targets targets = variables.getTargets();
+
+ ErrorMessageGenerator.create(ErrorMessageListUtils.getErrorMessageList(execution)).forEach(task::addOutput);
+
+ targets.getEntries().stream().sorted(Comparator.comparing(Target::getEndpointIdentifierValue)).forEach(target ->
+ {
+ String correlationKey = target.getCorrelationKey();
+
+ String statusCode = variables.getString(ConstantsPing.getBpmnExecutionVariableStatusCode(correlationKey));
+ if (ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_REACHABLE.equals(statusCode)
+ || ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_ALLOWED.equals(statusCode))
+ {
+ List errorMessages = ErrorMessageListUtils.getErrorMessageList(execution, correlationKey);
+ String errorMessage = errorMessages.get(0);
+ task.addOutput(PingStatusGenerator.createPingStatusOutput(target, statusCode, errorMessages));
+
+ if (ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_REACHABLE.equals(statusCode))
+ errorMailService.endpointNotReachableForPing(task.getIdElement(), target, errorMessage);
+ else if (ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_ALLOWED.equals(statusCode))
+ errorMailService.endpointReachablePingForbidden(task.getIdElement(), target, errorMessage);
+ }
+ else if (ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_MISSING.equals(statusCode))
+ {
+ List errorMessages = ErrorMessageListUtils.getErrorMessageList(execution, correlationKey);
+ task.addOutput(PingStatusGenerator.createPingStatusOutput(target, statusCode, errorMessages));
+
+ errorMailService.pongMessageNotReceived(task.getIdElement(), target);
+ }
+ else
+ {
+ int downloadResourceSizeBytes = variables
+ .getInteger(ConstantsPing.BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_SIZE_BYTES);
+ List errorMessageList = ErrorMessageListUtils.getErrorMessageList(execution, correlationKey);
+ if (downloadResourceSizeBytes >= 0) // if fat-ping
+ {
+ Integer downloadedBytes = variables
+ .getInteger(ConstantsPing.getBpmnExecutionVariableDownloadedBytes(correlationKey));
+ Long downloadedDurationMillis = variables
+ .getLong(ConstantsPing.getBpmnExecutionVariableDownloadedDurationMillis(correlationKey));
+
+ BigDecimal downloadSpeed = downloadedBytes != null && downloadedDurationMillis != null
+ ? NetworkSpeedCalculator.calculate(downloadedBytes, downloadedDurationMillis,
+ networkSpeedUnit)
+ : null;
+
+ Integer uploadedBytes = variables
+ .getInteger(ConstantsPing.getBpmnExecutionVariableUploadedBytes(correlationKey));
+ Long uploadedDurationMillis = variables
+ .getLong(ConstantsPing.getBpmnExecutionVariableUploadedDurationMillis(correlationKey));
+
+ BigDecimal uploadSpeed = uploadedBytes != null && uploadedDurationMillis != null
+ ? NetworkSpeedCalculator.calculate(uploadedBytes, uploadedDurationMillis, networkSpeedUnit)
+ : null;
+
+ task.addOutput(PingStatusGenerator.createPingStatusOutput(target, statusCode, errorMessageList,
+ downloadSpeed, uploadSpeed, networkSpeedUnit));
+ }
+ else // if slim-ping
+ {
+ task.addOutput(PingStatusGenerator.createPingStatusOutput(target, statusCode));
+ }
+ }
+ });
+
+ // TODO only send one combined status mail
+
+ variables.updateTask(task);
+
+ logger.debug("Successfully stored results for task {}", variables.getStartTask().getIdElement().getValue());
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/pong/DownloadResourceAndMeasureSpeed.java b/src/main/java/dev/dsf/bpe/service/pong/DownloadResourceAndMeasureSpeed.java
new file mode 100644
index 00000000..6692790d
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/pong/DownloadResourceAndMeasureSpeed.java
@@ -0,0 +1,57 @@
+package dev.dsf.bpe.service.pong;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.BinaryResourceDownloader;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class DownloadResourceAndMeasureSpeed extends AbstractServiceDelegate
+{
+ private final int maxDownloadSizeBytes;
+
+ public DownloadResourceAndMeasureSpeed(ProcessPluginApi api, int maxDownloadSizeBytes)
+ {
+ super(api);
+ this.maxDownloadSizeBytes = maxDownloadSizeBytes;
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(DownloadResourceAndMeasureSpeed.class, variables.getStartTask());
+ logger.debug("Starting resource download to measure speed...");
+
+ Task task = variables.getStartTask();
+
+ try
+ {
+ BinaryResourceDownloader.DownloadResult downloadResult = new BinaryResourceDownloader(logger)
+ .download(variables, api, task, maxDownloadSizeBytes);
+
+ if (downloadResult.getErrorMessage() == null)
+ {
+ variables.setInteger(ConstantsPing.getBpmnExecutionVariableDownloadedBytes(),
+ downloadResult.getDownloadedBytes());
+ variables.setLong(ConstantsPing.getBpmnExecutionVariableDownloadedDurationMillis(),
+ downloadResult.getDownloadedDurationMillis());
+ }
+ else
+ {
+ throw new BpmnError(ConstantsPing.BPMN_ERROR_CODE_RESOURCE_DOWNLOAD_ERROR,
+ downloadResult.getErrorMessage());
+ }
+
+ logger.debug("Completed resource download and measured speed.");
+ }
+ catch (Exception e)
+ {
+ throw new BpmnError(ConstantsPing.BPMN_ERROR_CODE_RESOURCE_DOWNLOAD_ERROR, e.getMessage());
+ }
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/pong/EstimateCleanupTimerDuration.java b/src/main/java/dev/dsf/bpe/service/pong/EstimateCleanupTimerDuration.java
new file mode 100644
index 00000000..49fffc6f
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/pong/EstimateCleanupTimerDuration.java
@@ -0,0 +1,41 @@
+package dev.dsf.bpe.service.pong;
+
+import java.time.Duration;
+import java.util.Optional;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class EstimateCleanupTimerDuration extends AbstractServiceDelegate
+{
+ public EstimateCleanupTimerDuration(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(EstimateCleanupTimerDuration.class, variables.getStartTask());
+
+ logger.debug("Estimating cleanup timer duration...");
+ final long minTimerDurationMillis = 20000;
+ long downloadedDurationMillis = Optional
+ .ofNullable(variables.getLong(ConstantsPing.getBpmnExecutionVariableDownloadedDurationMillis()))
+ .orElse(0L);
+ long timerDurationMillis = downloadedDurationMillis > Long.MAX_VALUE / 10 - minTimerDurationMillis
+ ? Long.MAX_VALUE
+ : downloadedDurationMillis * 10 + minTimerDurationMillis;
+
+ String cleanUpTimerDuration = Duration.ofMillis(timerDurationMillis).toString();
+ variables.setString("cleanupTimerDuration", cleanUpTimerDuration);
+
+ logger.debug("Estimated cleanup timer duration as {}", cleanUpTimerDuration);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/pong/LogAndSaveAndStoreError.java b/src/main/java/dev/dsf/bpe/service/pong/LogAndSaveAndStoreError.java
new file mode 100644
index 00000000..d4734d3c
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/pong/LogAndSaveAndStoreError.java
@@ -0,0 +1,39 @@
+package dev.dsf.bpe.service.pong;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.ErrorMessageListUtils;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.util.task.output.generator.PingStatusGenerator;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Target;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class LogAndSaveAndStoreError extends AbstractServiceDelegate
+{
+ public LogAndSaveAndStoreError(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(LogAndSaveAndStoreError.class, variables.getStartTask());
+ Target target = variables.getTarget();
+ Task startTask = variables.getStartTask();
+
+ String errorMessage = variables
+ .getString(ConstantsPing.BPMN_EXECUTION_VARIABLE_RESOURCE_DOWNLOAD_ERROR_MESSAGE);
+ ErrorMessageListUtils.add(errorMessage, delegateExecution);
+ PingStatusGenerator.updatePongStatusOutput(startTask,
+ ErrorMessageListUtils.getErrorMessageList(delegateExecution));
+ variables.updateTask(startTask);
+
+ logger.info("Error while trying to download resource from {}: {}", target.getEndpointUrl(), errorMessage);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/pong/LogAndSaveUploadErrorPong.java b/src/main/java/dev/dsf/bpe/service/pong/LogAndSaveUploadErrorPong.java
new file mode 100644
index 00000000..6ee624ba
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/pong/LogAndSaveUploadErrorPong.java
@@ -0,0 +1,32 @@
+package dev.dsf.bpe.service.pong;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.ErrorMessageListUtils;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class LogAndSaveUploadErrorPong extends AbstractServiceDelegate
+{
+ public LogAndSaveUploadErrorPong(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
+ {
+ Task startTask = variables.getStartTask();
+ PingPongLogger logger = new PingPongLogger(LogAndSaveUploadErrorPong.class, startTask);
+
+ String errorMessage = variables.getString(ConstantsPing.BPMN_EXECUTION_VARIABLE_RESOURCE_UPLOAD_ERROR_MESSAGE);
+ ErrorMessageListUtils.add(errorMessage, execution);
+
+ logger.info("Error while storing binary resource for download: {}", errorMessage);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/LogPing.java b/src/main/java/dev/dsf/bpe/service/pong/LogPing.java
similarity index 86%
rename from src/main/java/dev/dsf/bpe/service/LogPing.java
rename to src/main/java/dev/dsf/bpe/service/pong/LogPing.java
index cbfc2867..54ce1e91 100644
--- a/src/main/java/dev/dsf/bpe/service/LogPing.java
+++ b/src/main/java/dev/dsf/bpe/service/pong/LogPing.java
@@ -1,22 +1,19 @@
-package dev.dsf.bpe.service;
+package dev.dsf.bpe.service.pong;
import org.camunda.bpm.engine.delegate.BpmnError;
import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.logging.PingPongLogger;
import dev.dsf.bpe.v1.ProcessPluginApi;
import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
import dev.dsf.bpe.v1.variables.Variables;
public class LogPing extends AbstractServiceDelegate
{
- private static final Logger logger = LoggerFactory.getLogger(LogPing.class);
-
public LogPing(ProcessPluginApi api)
{
super(api);
@@ -25,6 +22,8 @@ public LogPing(ProcessPluginApi api)
@Override
protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
{
+ PingPongLogger logger = new PingPongLogger(LogPing.class, variables.getStartTask());
+
Task task = variables.getLatestTask();
logger.info("PING from {} (endpoint: {})", task.getRequester().getIdentifier().getValue(),
diff --git a/src/main/java/dev/dsf/bpe/service/pong/SaveTimeoutError.java b/src/main/java/dev/dsf/bpe/service/pong/SaveTimeoutError.java
new file mode 100644
index 00000000..eba52fa3
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/pong/SaveTimeoutError.java
@@ -0,0 +1,34 @@
+package dev.dsf.bpe.service.pong;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.ErrorMessageListUtils;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class SaveTimeoutError extends AbstractServiceDelegate
+{
+ public SaveTimeoutError(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
+ {
+ Task startTask = variables.getStartTask();
+ PingPongLogger logger = new PingPongLogger(SaveTimeoutError.class, startTask);
+ logger.debug("Storing timeout error...");
+
+ String errorMessage = ConstantsPing.PONG_ERROR_MESSAGE_CLEANUP_TIMEOUT;
+
+ ErrorMessageListUtils.add(errorMessage, execution);
+
+ logger.debug("Stored timeout error: {}", errorMessage);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/SelectPongTarget.java b/src/main/java/dev/dsf/bpe/service/pong/SelectPongTarget.java
similarity index 70%
rename from src/main/java/dev/dsf/bpe/service/SelectPongTarget.java
rename to src/main/java/dev/dsf/bpe/service/pong/SelectPongTarget.java
index 7e3f0d3d..efd40d45 100644
--- a/src/main/java/dev/dsf/bpe/service/SelectPongTarget.java
+++ b/src/main/java/dev/dsf/bpe/service/pong/SelectPongTarget.java
@@ -1,15 +1,13 @@
-package dev.dsf.bpe.service;
+package dev.dsf.bpe.service.pong;
import org.camunda.bpm.engine.delegate.BpmnError;
import org.camunda.bpm.engine.delegate.DelegateExecution;
-import org.hl7.fhir.r4.model.Identifier;
-import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.Task;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.service.ping.SelectPingTargets;
+import dev.dsf.bpe.util.logging.PingPongLogger;
import dev.dsf.bpe.v1.ProcessPluginApi;
import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
import dev.dsf.bpe.v1.constants.CodeSystems.BpmnMessage;
@@ -17,8 +15,6 @@
public class SelectPongTarget extends AbstractServiceDelegate implements InitializingBean
{
- private static final Logger logger = LoggerFactory.getLogger(SelectPongTarget.class);
-
public SelectPongTarget(ProcessPluginApi api)
{
super(api);
@@ -27,12 +23,16 @@ public SelectPongTarget(ProcessPluginApi api)
@Override
protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
{
+ PingPongLogger logger = new PingPongLogger(SelectPingTargets.class, variables.getStartTask());
+ logger.debug("Selecting pong targets...");
+
Task task = variables.getStartTask();
String correlationKey = api.getTaskHelper()
.getFirstInputParameterStringValue(task, BpmnMessage.URL, BpmnMessage.Codes.CORRELATION_KEY).get();
String targetOrganizationIdentifierValue = task.getRequester().getIdentifier().getValue();
- String targetEndpointIdentifierValue = getEndpointIdentifierValue(task);
+ String targetEndpointIdentifierValue = variables
+ .getString(ConstantsPing.BPMN_EXECUTION_VARIABLE_PONG_TARGET_ENDPOINT_IDENTIFIER);
String targetEndpointAddress = api.getEndpointProvider().getEndpointAddress(targetEndpointIdentifierValue)
.orElseThrow(() ->
@@ -45,13 +45,6 @@ protected void doExecute(DelegateExecution execution, Variables variables) throw
variables.setTarget(variables.createTarget(targetOrganizationIdentifierValue, targetEndpointIdentifierValue,
targetEndpointAddress, correlationKey));
- }
-
- private String getEndpointIdentifierValue(Task task)
- {
- return api.getTaskHelper()
- .getFirstInputParameterValue(task, ConstantsPing.CODESYSTEM_DSF_PING,
- ConstantsPing.CODESYSTEM_DSF_PING_VALUE_ENDPOINT_IDENTIFIER, Reference.class)
- .map(Reference::getIdentifier).map(Identifier::getValue).get();
+ logger.debug("Selected pong targets.");
}
}
diff --git a/src/main/java/dev/dsf/bpe/service/pong/SetEndpointIdentifier.java b/src/main/java/dev/dsf/bpe/service/pong/SetEndpointIdentifier.java
new file mode 100644
index 00000000..e2673630
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/pong/SetEndpointIdentifier.java
@@ -0,0 +1,43 @@
+package dev.dsf.bpe.service.pong;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.Identifier;
+import org.hl7.fhir.r4.model.Reference;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class SetEndpointIdentifier extends AbstractServiceDelegate
+{
+ public SetEndpointIdentifier(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
+ {
+ PingPongLogger logger = new PingPongLogger(SetEndpointIdentifier.class, variables.getStartTask());
+ logger.debug("Setting endpoint identifier...");
+
+ Task task = variables.getStartTask();
+ String endpointIdentifierValue = getEndpointIdentifierValue(task);
+ variables.setString(ConstantsPing.BPMN_EXECUTION_VARIABLE_PONG_TARGET_ENDPOINT_IDENTIFIER,
+ endpointIdentifierValue);
+
+ logger.debug("Set endpoint identifier to " + endpointIdentifierValue);
+ }
+
+ private String getEndpointIdentifierValue(Task task)
+ {
+ return api.getTaskHelper()
+ .getFirstInputParameterValue(task, ConstantsPing.CODESYSTEM_DSF_PING,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_ENDPOINT_IDENTIFIER, Reference.class)
+ .map(Reference::getIdentifier).map(Identifier::getValue).get();
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/pong/StoreDownloadSpeed.java b/src/main/java/dev/dsf/bpe/service/pong/StoreDownloadSpeed.java
new file mode 100644
index 00000000..afc3d91d
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/pong/StoreDownloadSpeed.java
@@ -0,0 +1,48 @@
+package dev.dsf.bpe.service.pong;
+
+import java.math.BigDecimal;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.util.task.NetworkSpeedCalculator;
+import dev.dsf.bpe.util.task.output.generator.PingStatusGenerator;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class StoreDownloadSpeed extends AbstractServiceDelegate
+{
+ private final String networkSpeedUnit;
+
+ public StoreDownloadSpeed(ProcessPluginApi api, String networkSpeedUnit)
+ {
+ super(api);
+ this.networkSpeedUnit = networkSpeedUnit;
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
+ {
+ Task startTask = variables.getStartTask();
+ PingPongLogger logger = new PingPongLogger(StoreDownloadSpeed.class, startTask);
+ logger.debug("Storing download speed...");
+
+ int downloadedBytes = variables.getInteger(ConstantsPing.getBpmnExecutionVariableDownloadedBytes());
+ long downloadedDurationMillis = variables
+ .getLong(ConstantsPing.getBpmnExecutionVariableDownloadedDurationMillis());
+
+ BigDecimal downloadSpeed = NetworkSpeedCalculator.calculate(downloadedBytes, downloadedDurationMillis,
+ networkSpeedUnit);
+
+ PingStatusGenerator.updatePongStatusOutput(startTask,
+ ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_RESOURCE_DOWNLOADED);
+ PingStatusGenerator.updatePongStatusOutputDownloadSpeed(startTask, downloadSpeed, networkSpeedUnit);
+
+ variables.updateTask(startTask);
+ logger.debug("Stored download speed: " + downloadSpeed + " " + networkSpeedUnit);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/pong/StoreErrors.java b/src/main/java/dev/dsf/bpe/service/pong/StoreErrors.java
new file mode 100644
index 00000000..59e8a1a1
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/pong/StoreErrors.java
@@ -0,0 +1,33 @@
+package dev.dsf.bpe.service.pong;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.util.ErrorMessageListUtils;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.util.task.output.generator.PingStatusGenerator;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class StoreErrors extends AbstractServiceDelegate
+{
+ public StoreErrors(ProcessPluginApi api)
+ {
+ super(api);
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution execution, Variables variables) throws BpmnError, Exception
+ {
+ Task startTask = variables.getStartTask();
+ PingPongLogger logger = new PingPongLogger(StoreErrors.class, startTask);
+ logger.debug("Storing errors...");
+
+ PingStatusGenerator.updatePongStatusOutput(startTask, ErrorMessageListUtils.getErrorMessageList(execution));
+
+ variables.updateTask(startTask);
+ logger.debug("Stored errors in task: " + startTask.getIdElement().getValue());
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/service/pong/StoreUploadSpeed.java b/src/main/java/dev/dsf/bpe/service/pong/StoreUploadSpeed.java
new file mode 100644
index 00000000..e38b4d8f
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/service/pong/StoreUploadSpeed.java
@@ -0,0 +1,65 @@
+package dev.dsf.bpe.service.pong;
+
+import java.math.BigDecimal;
+import java.util.Optional;
+
+import org.camunda.bpm.engine.delegate.BpmnError;
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.hl7.fhir.r4.model.DecimalType;
+import org.hl7.fhir.r4.model.IntegerType;
+import org.hl7.fhir.r4.model.PrimitiveType;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.util.task.NetworkSpeedCalculator;
+import dev.dsf.bpe.util.task.output.generator.PingStatusGenerator;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
+import dev.dsf.bpe.v1.variables.Variables;
+
+public class StoreUploadSpeed extends AbstractServiceDelegate
+{
+ private final String networkSpeedUnit;
+
+ public StoreUploadSpeed(ProcessPluginApi api, String networkSpeedUnit)
+ {
+ super(api);
+ this.networkSpeedUnit = networkSpeedUnit;
+ }
+
+ @Override
+ protected void doExecute(DelegateExecution delegateExecution, Variables variables) throws BpmnError, Exception
+ {
+ Task startTask = variables.getStartTask();
+ Task cleanup = variables.getLatestTask();
+ PingPongLogger logger = new PingPongLogger(LogPing.class, startTask);
+ logger.debug("Storing upload speed...");
+
+ Optional uploadedBytesTaskInput = getUploadedBytes(cleanup);
+ Optional uploadedDurationMillisTaskInput = getUploadedDurationMillis(cleanup);
+ int uploadedBytes = uploadedBytesTaskInput.map(PrimitiveType::getValue).orElse(0);
+ long uploadedDurationMillis = uploadedDurationMillisTaskInput
+ .map(decimalType -> decimalType.getValue().longValue()).orElse(0L);
+
+ BigDecimal uploadSpeed = NetworkSpeedCalculator.calculate(uploadedBytes, uploadedDurationMillis,
+ networkSpeedUnit);
+
+ PingStatusGenerator.updatePongStatusOutputUploadSpeed(startTask, uploadSpeed, networkSpeedUnit);
+
+ variables.updateTask(startTask);
+ logger.debug("Stored upload speed: " + uploadSpeed + " " + networkSpeedUnit);
+ }
+
+ private Optional getUploadedBytes(Task task)
+ {
+ return api.getTaskHelper().getFirstInputParameterValue(task, ConstantsPing.CODESYSTEM_DSF_PING,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOADED_BYTES, IntegerType.class);
+ }
+
+ private Optional getUploadedDurationMillis(Task task)
+ {
+ return api.getTaskHelper().getFirstInputParameterValue(task, ConstantsPing.CODESYSTEM_DSF_PING,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOADED_DURATION_MILLIS, DecimalType.class);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/spring/config/PingConfig.java b/src/main/java/dev/dsf/bpe/spring/config/PingConfig.java
index 85c02919..164d6145 100644
--- a/src/main/java/dev/dsf/bpe/spring/config/PingConfig.java
+++ b/src/main/java/dev/dsf/bpe/spring/config/PingConfig.java
@@ -7,20 +7,35 @@
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
+import dev.dsf.bpe.listener.PingPongDeploymentStateListener;
import dev.dsf.bpe.listener.SetCorrelationKeyListener;
import dev.dsf.bpe.mail.ErrorMailService;
+import dev.dsf.bpe.message.CleanupPong;
import dev.dsf.bpe.message.SendPing;
import dev.dsf.bpe.message.SendPong;
import dev.dsf.bpe.message.SendStartPing;
-import dev.dsf.bpe.service.LogNoResponse;
-import dev.dsf.bpe.service.LogPing;
-import dev.dsf.bpe.service.LogPong;
-import dev.dsf.bpe.service.LogSendError;
-import dev.dsf.bpe.service.SaveResults;
-import dev.dsf.bpe.service.SelectPingTargets;
-import dev.dsf.bpe.service.SelectPongTarget;
-import dev.dsf.bpe.service.SetTargetAndConfigureTimer;
-import dev.dsf.bpe.util.PingStatusGenerator;
+import dev.dsf.bpe.service.Cleanup;
+import dev.dsf.bpe.service.GenerateAndStoreResource;
+import dev.dsf.bpe.service.SetDownloadResourceSize;
+import dev.dsf.bpe.service.autostart.SetTargetAndConfigureTimer;
+import dev.dsf.bpe.service.ping.DownloadResourceAndMeasureSpeedInSubProcess;
+import dev.dsf.bpe.service.ping.LogAndSaveError;
+import dev.dsf.bpe.service.ping.LogAndSaveNoResponse;
+import dev.dsf.bpe.service.ping.LogAndSaveUploadErrorPing;
+import dev.dsf.bpe.service.ping.SavePong;
+import dev.dsf.bpe.service.ping.SelectPingTargets;
+import dev.dsf.bpe.service.ping.StoreResults;
+import dev.dsf.bpe.service.pong.DownloadResourceAndMeasureSpeed;
+import dev.dsf.bpe.service.pong.EstimateCleanupTimerDuration;
+import dev.dsf.bpe.service.pong.LogAndSaveAndStoreError;
+import dev.dsf.bpe.service.pong.LogAndSaveUploadErrorPong;
+import dev.dsf.bpe.service.pong.LogPing;
+import dev.dsf.bpe.service.pong.SaveTimeoutError;
+import dev.dsf.bpe.service.pong.SelectPongTarget;
+import dev.dsf.bpe.service.pong.SetEndpointIdentifier;
+import dev.dsf.bpe.service.pong.StoreDownloadSpeed;
+import dev.dsf.bpe.service.pong.StoreErrors;
+import dev.dsf.bpe.service.pong.StoreUploadSpeed;
import dev.dsf.bpe.v1.ProcessPluginApi;
import dev.dsf.bpe.v1.documentation.ProcessDocumentation;
@@ -30,14 +45,58 @@ public class PingConfig
@Autowired
private ProcessPluginApi api;
- @ProcessDocumentation(description = "To enable a mail being send if the ping process fails, set to 'true'. This requires the SMPT mail service client to be configured in the DSF", processNames = "dsfdev_ping")
+ @ProcessDocumentation(description = "To enable a mail being sent if the ping process fails, set to 'true'. This requires the SMPT mail service client to be configured in the DSF", processNames = "dsfdev_ping")
@Value("${dev.dsf.dsf.bpe.ping.mail.onPingProcessFailed:false}")
private boolean sendPingProcessFailedMail;
- @ProcessDocumentation(description = "To enable a mail being send if the pong process fails, set to 'true'. This requires the SMPT mail service client to be configured in the DSF", processNames = "dsfdev_pong")
+ @ProcessDocumentation(description = "To enable a mail being sent if the pong process fails, set to 'true'. This requires the SMPT mail service client to be configured in the DSF", processNames = "dsfdev_pong")
@Value("${dev.dsf.dsf.bpe.ping.mail.onPongProcessFailed:false}")
private boolean sendPongProcessFailedMail;
+ @ProcessDocumentation(description = "Sets the download limit on resource downloads, essentially limiting the amount of data downloaded from other ping instances. Setting this to a negative value will disable resource downloads, effectively resulting in running the slim (\"old\") ping process.", processNames = "dsfdev_ping, dsfdev_pong")
+ @Value("${dev.dsf.bpe.ping.maxDownloadSizeBytes:10000000}")
+ private int maxDownloadSizeBytes;
+
+ @ProcessDocumentation(description = "Sets the upload limit on resource uploads, essentially limiting the amount of data other ping instances are able to download from this instance.", processNames = {
+ "dsfdev_ping", "dsfdev_pong" })
+ @Value("${dev.dsf.bpe.ping.maxUploadSizeBytes:10000000}")
+ private int maxUploadSizeBytes;
+
+ @ProcessDocumentation(description = "Unit to display upload and download speeds in. Eligible values be: \"bits-per-second\", \"bytes-per-second\", \"megabits-per-second\", \"megabytes-per-second\". Default is \"megabytes-per-second\".", processNames = {
+ "dsfdev_ping", "dsfdev_pong" })
+ @Value("${dev.dsf.bpe.ping.networkSpeedUnit:megabytes-per-second}")
+ private String networkSpeedUnit;
+
+ public String getNetworkSpeedUnit()
+ {
+ return networkSpeedUnit;
+ }
+
+ public void setNetworkSpeedUnit(String networkSpeedUnit)
+ {
+ this.networkSpeedUnit = networkSpeedUnit;
+ }
+
+ public int getMaxDownloadSizeBytes()
+ {
+ return maxDownloadSizeBytes;
+ }
+
+ public void setMaxDownloadSizeBytes(int maxDownloadSizeBytes)
+ {
+ this.maxDownloadSizeBytes = maxDownloadSizeBytes;
+ }
+
+ public int getMaxUploadSizeBytes()
+ {
+ return maxUploadSizeBytes;
+ }
+
+ public void setMaxUploadSizeBytes(int maxUploadSizeBytes)
+ {
+ this.maxUploadSizeBytes = maxUploadSizeBytes;
+ }
+
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public SetTargetAndConfigureTimer setTargetAndConfigureTimer()
@@ -52,12 +111,6 @@ public SendStartPing sendStartPing()
return new SendStartPing(api);
}
- @Bean
- public PingStatusGenerator responseGenerator()
- {
- return new PingStatusGenerator();
- }
-
@Bean
public ErrorMailService errorLogger()
{
@@ -88,50 +141,169 @@ public SetCorrelationKeyListener setCorrelationKeyListener()
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- public LogPong logPong()
+ public StoreResults savePingResults()
+ {
+ return new StoreResults(api, errorLogger(), networkSpeedUnit);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public LogPing logPing()
{
- return new LogPong(api);
+ return new LogPing(api);
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- public LogNoResponse logNoResponse()
+ public SelectPongTarget selectPongTarget()
{
- return new LogNoResponse(api);
+ return new SelectPongTarget(api);
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- public LogSendError logSendError()
+ public SendPong sendPong()
{
- return new LogSendError(api);
+ return new SendPong(api, errorLogger());
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- public SaveResults savePingResults()
+ public LogAndSaveNoResponse logAndSaveNoResponse()
{
- return new SaveResults(api, responseGenerator(), errorLogger());
+ return new LogAndSaveNoResponse(api);
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- public LogPing logPing()
+ public CleanupPong cleanupPong()
{
- return new LogPing(api);
+ return new CleanupPong(api);
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- public SelectPongTarget selectPongTarget()
+ public DownloadResourceAndMeasureSpeed downloadResourceAndMeasureSpeed()
{
- return new SelectPongTarget(api);
+ return new DownloadResourceAndMeasureSpeed(api, (int) maxDownloadSizeBytes);
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
- public SendPong sendPong()
+ public DownloadResourceAndMeasureSpeedInSubProcess downloadResourceAndMeasureSpeedInSubProcess()
+ {
+ return new DownloadResourceAndMeasureSpeedInSubProcess(api, (int) maxDownloadSizeBytes);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public Cleanup cleanup()
+ {
+ return new Cleanup(api);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public LogAndSaveAndStoreError logAndSaveAndStoreError()
+ {
+ return new LogAndSaveAndStoreError(api);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public LogAndSaveError logAndSaveError()
+ {
+ return new LogAndSaveError(api);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public StoreUploadSpeed storeDownloadSpeeds()
+ {
+ return new StoreUploadSpeed(api, networkSpeedUnit);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public EstimateCleanupTimerDuration estimateCleanupTimerDuration()
+ {
+ return new EstimateCleanupTimerDuration(api);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public SetDownloadResourceSize setDownloadResourceSize()
+ {
+ return new SetDownloadResourceSize(api, maxDownloadSizeBytes);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public SavePong savePong()
+ {
+ return new SavePong(api);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public SetEndpointIdentifier setEndpointIdentifier()
+ {
+ return new SetEndpointIdentifier(api);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public PingPongDeploymentStateListener pingPongDeploymentStateListener()
+ {
+ return new PingPongDeploymentStateListener(this);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public StoreDownloadSpeed storeDownloadSpeed()
+ {
+ return new StoreDownloadSpeed(api, networkSpeedUnit);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public dev.dsf.bpe.service.ping.LogAndSaveSendError logAndSaveSendError()
+ {
+ return new dev.dsf.bpe.service.ping.LogAndSaveSendError(api);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public GenerateAndStoreResource generateAndStoreResource()
+ {
+ return new GenerateAndStoreResource(api, maxUploadSizeBytes);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public SaveTimeoutError saveTimeoutError()
+ {
+ return new SaveTimeoutError(api);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public StoreErrors storeErrors()
+ {
+ return new StoreErrors(api);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public LogAndSaveUploadErrorPing logAndSaveUploadErrorPing()
+ {
+ return new LogAndSaveUploadErrorPing(api);
+ }
+
+ @Bean
+ @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
+ public LogAndSaveUploadErrorPong logAndSaveUploadErrorPong()
{
- return new SendPong(api, responseGenerator(), errorLogger());
+ return new LogAndSaveUploadErrorPong(api);
}
}
diff --git a/src/main/java/dev/dsf/bpe/util/BinaryResourceDownloader.java b/src/main/java/dev/dsf/bpe/util/BinaryResourceDownloader.java
new file mode 100644
index 00000000..39179fad
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/BinaryResourceDownloader.java
@@ -0,0 +1,129 @@
+package dev.dsf.bpe.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.hl7.fhir.r4.model.IdType;
+import org.hl7.fhir.r4.model.Reference;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.util.logging.PingPongLogger;
+import dev.dsf.bpe.v1.ProcessPluginApi;
+import dev.dsf.bpe.v1.variables.Variables;
+import jakarta.ws.rs.WebApplicationException;
+
+public class BinaryResourceDownloader
+{
+ private final PingPongLogger logger;
+
+ public BinaryResourceDownloader(PingPongLogger logger)
+ {
+ this.logger = logger;
+ }
+
+ public DownloadResult download(Variables variables, ProcessPluginApi api, Task task, int maxDownloadSizeBytes)
+ throws Exception
+ {
+ DownloadResult downloadResult;
+
+ int downloadResourceSizeBytes = variables
+ .getInteger(ConstantsPing.BPMN_EXECUTION_VARIABLE_DOWNLOAD_RESOURCE_SIZE_BYTES);
+
+ Reference downloadResourceReference = api.getTaskHelper()
+ .getFirstInputParameterValue(task, ConstantsPing.CODESYSTEM_DSF_PING,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOAD_RESOURCE_REFERENCE, Reference.class)
+ .orElseThrow(() -> new Exception("Unable to download resource. No reference provided in message."));
+
+ IdType downloadResourceReferenceIdType = new IdType(downloadResourceReference.getReference());
+ String downloadResourceReferenceId = downloadResourceReferenceIdType.getIdPart();
+ String webserviceUrl = downloadResourceReferenceIdType.getBaseUrl();
+ try
+ {
+ InputStream binaryResourceInputStream = api.getFhirWebserviceClientProvider()
+ .getWebserviceClient(webserviceUrl)
+ .readBinary(downloadResourceReferenceId, ConstantsPing.DOWNLOAD_RESOURCE_MIME_TYPE);
+
+ try (binaryResourceInputStream)
+ {
+ logger.info(
+ "Downloading resource for: '{}'. Requested resource size is {} bytes, maximum downloadable size is {} bytes...",
+ downloadResourceReference.getReference(), downloadResourceSizeBytes, maxDownloadSizeBytes);
+ long downloadStartTime = System.currentTimeMillis();
+ int numBytes = Math.min(downloadResourceSizeBytes, maxDownloadSizeBytes);
+ binaryResourceInputStream.skipNBytes(numBytes);
+ long downloadEndTime = System.currentTimeMillis();
+ long downloadedDurationMillis = downloadEndTime - downloadStartTime;
+ downloadResult = new DownloadResult(numBytes, downloadedDurationMillis);
+ logger.info("Finished downloading {} bytes. Took {}", numBytes,
+ toHoursMinutesSecondsMilliseconds(downloadedDurationMillis));
+
+ }
+ catch (IOException e)
+ {
+ String error = "Encountered an error while downloading resource: " + e.getMessage();
+ logger.error(error);
+ downloadResult = new DownloadResult(error);
+ }
+ }
+ catch (WebApplicationException e)
+ {
+ String error = "Encountered an error while trying to download resource: "
+ + e.getResponse().getStatusInfo().getStatusCode() + " " + e.getMessage();
+ logger.error(error);
+ downloadResult = new DownloadResult(error);
+ }
+ catch (Exception e)
+ {
+ String error = "Encountered an error while trying to download resource: " + e.getMessage();
+ logger.error(error);
+ downloadResult = new DownloadResult(error);
+ }
+ return downloadResult;
+ }
+
+ private String toHoursMinutesSecondsMilliseconds(long millis)
+ {
+ long hours = (millis / 1000) / 60 / 60 % 24;
+ long minutes = (millis / 1000) / 60 % 60;
+ long seconds = (millis / 1000) % 60;
+ long milliSeconds = millis % 1000;
+ return String.format("%02d:%02d:%02d:%03d (h:m:s:ms)", hours, minutes, seconds, milliSeconds);
+ }
+
+ public static class DownloadResult
+ {
+ private final int downloadedBytes;
+ private final long downloadedDurationMillis;
+ private final String errorMessage;
+
+ public DownloadResult(int downloadedBytes, long downloadedDurationMillis)
+ {
+ this.downloadedBytes = downloadedBytes;
+ this.downloadedDurationMillis = downloadedDurationMillis;
+ errorMessage = null;
+ }
+
+ public DownloadResult(String errorMessage)
+ {
+ downloadedBytes = 0;
+ downloadedDurationMillis = 0;
+ this.errorMessage = errorMessage;
+ }
+
+ public int getDownloadedBytes()
+ {
+ return downloadedBytes;
+ }
+
+ public long getDownloadedDurationMillis()
+ {
+ return downloadedDurationMillis;
+ }
+
+ public String getErrorMessage()
+ {
+ return errorMessage;
+ }
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/ErrorMessageListUtils.java b/src/main/java/dev/dsf/bpe/util/ErrorMessageListUtils.java
new file mode 100644
index 00000000..f2857330
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/ErrorMessageListUtils.java
@@ -0,0 +1,88 @@
+package dev.dsf.bpe.util;
+
+import java.util.List;
+import java.util.Vector;
+
+import org.camunda.bpm.engine.delegate.DelegateExecution;
+
+import dev.dsf.bpe.ConstantsPing;
+
+public class ErrorMessageListUtils
+{
+ public static List addAll(List errors, DelegateExecution execution)
+ {
+ List errorList = getErrorMessageList(execution);
+ if (errors == null)
+ return errorList;
+ errorList.addAll(errors);
+ return errorList;
+ }
+
+ public static List addAll(List errors, DelegateExecution execution, String correlationKey)
+ {
+ List errorList = correlationKey != null ? getErrorMessageList(execution, correlationKey)
+ : getErrorMessageList(execution);
+ if (errors == null)
+ return errorList;
+ errorList.addAll(errors);
+ return errorList;
+ }
+
+ public static List add(String error, DelegateExecution execution)
+ {
+ return add(error, execution, null);
+ }
+
+ public static List add(String error, DelegateExecution execution, String correlationKey)
+ {
+ if (correlationKey != null)
+ {
+ return add(error, ConstantsPing.getBpmnExecutionVariableErrorMessageList(correlationKey), execution);
+ }
+ else
+ {
+ return add(error, ConstantsPing.getBpmnExecutionVariableErrorMessageList(), execution);
+ }
+ }
+
+ public static List getErrorMessageList(DelegateExecution execution)
+ {
+ return getErrorMessageList(execution, null);
+ }
+
+ @SuppressWarnings("unchecked")
+ public static List getErrorMessageList(DelegateExecution execution, String correlationKey)
+ {
+ List errorMessages = correlationKey != null
+ ? (List) execution
+ .getVariable(ConstantsPing.getBpmnExecutionVariableErrorMessageList(correlationKey))
+ : (List) execution.getVariable(ConstantsPing.getBpmnExecutionVariableErrorMessageList());
+ if (errorMessages == null)
+ {
+ errorMessages = new Vector<>();
+ if (correlationKey != null)
+ {
+ execution.setVariable(ConstantsPing.getBpmnExecutionVariableErrorMessageList(correlationKey),
+ errorMessages);
+ }
+ else
+ {
+ execution.setVariable(ConstantsPing.getBpmnExecutionVariableErrorMessageList(), errorMessages);
+ }
+ }
+ return errorMessages;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static List add(String error, String variableName, DelegateExecution execution)
+ {
+ List errorMessages = (List) execution.getVariable(variableName);
+ if (errorMessages == null)
+ {
+ errorMessages = new Vector<>();
+ execution.setVariable(variableName, errorMessages);
+ }
+ errorMessages.add(error);
+ return errorMessages;
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/PingStatusGenerator.java b/src/main/java/dev/dsf/bpe/util/PingStatusGenerator.java
deleted file mode 100644
index 142ded7d..00000000
--- a/src/main/java/dev/dsf/bpe/util/PingStatusGenerator.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package dev.dsf.bpe.util;
-
-import org.hl7.fhir.r4.model.Coding;
-import org.hl7.fhir.r4.model.Extension;
-import org.hl7.fhir.r4.model.StringType;
-import org.hl7.fhir.r4.model.Task.TaskOutputComponent;
-
-import dev.dsf.bpe.ConstantsPing;
-import dev.dsf.bpe.v1.constants.NamingSystems.EndpointIdentifier;
-import dev.dsf.bpe.v1.constants.NamingSystems.OrganizationIdentifier;
-import dev.dsf.bpe.v1.variables.Target;
-
-public class PingStatusGenerator
-{
- public TaskOutputComponent createPingStatusOutput(Target target, String statusCode)
- {
- return createPingStatusOutput(target, statusCode, null);
- }
-
- public TaskOutputComponent createPingStatusOutput(Target target, String statusCode, String errorMessage)
- {
- return createStatusOutput(target, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PING_STATUS, statusCode,
- errorMessage);
- }
-
- public TaskOutputComponent createPongStatusOutput(Target target, String statusCode)
- {
- return createPongStatusOutput(target, statusCode, null);
- }
-
- public TaskOutputComponent createPongStatusOutput(Target target, String statusCode, String errorMessage)
- {
- return createStatusOutput(target, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PONG_STATUS, statusCode,
- errorMessage);
- }
-
- private TaskOutputComponent createStatusOutput(Target target, String outputParameter, String statusCode,
- String errorMessage)
- {
- TaskOutputComponent output = new TaskOutputComponent();
- output.setValue(new Coding().setSystem(ConstantsPing.CODESYSTEM_DSF_PING_STATUS).setCode(statusCode));
- output.getType().addCoding().setSystem(ConstantsPing.CODESYSTEM_DSF_PING).setCode(outputParameter);
-
- Extension extension = output.addExtension();
- extension.setUrl(ConstantsPing.EXTENSION_URL_PING_STATUS);
- extension.addExtension(ConstantsPing.EXTENSION_URL_CORRELATION_KEY, new StringType(target.getCorrelationKey()));
- extension.addExtension().setUrl(ConstantsPing.EXTENSION_URL_ORGANIZATION_IDENTIFIER)
- .setValue(OrganizationIdentifier.withValue(target.getOrganizationIdentifierValue()));
- extension.addExtension().setUrl(ConstantsPing.EXTENSION_URL_ENDPOINT_IDENTIFIER)
- .setValue(EndpointIdentifier.withValue(target.getEndpointIdentifierValue()));
- if (errorMessage != null)
- extension.addExtension().setUrl(ConstantsPing.EXTENSION_URL_ERROR_MESSAGE)
- .setValue(new StringType(errorMessage));
-
- return output;
- }
-}
diff --git a/src/main/java/dev/dsf/bpe/util/ReadAccessTagGenerator.java b/src/main/java/dev/dsf/bpe/util/ReadAccessTagGenerator.java
new file mode 100644
index 00000000..cf2c51df
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/ReadAccessTagGenerator.java
@@ -0,0 +1,16 @@
+package dev.dsf.bpe.util;
+
+import org.hl7.fhir.r4.model.Coding;
+
+import dev.dsf.bpe.ConstantsPing;
+
+public class ReadAccessTagGenerator
+{
+ public static Coding create(String accessLevel)
+ {
+ Coding tag = new Coding();
+ tag.setSystem(ConstantsPing.CODESYSTEM_READ_ACCESS_TAG);
+ tag.setCode(accessLevel);
+ return tag;
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/VersionUtils.java b/src/main/java/dev/dsf/bpe/util/VersionUtils.java
new file mode 100644
index 00000000..b112adef
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/VersionUtils.java
@@ -0,0 +1,16 @@
+package dev.dsf.bpe.util;
+
+import dev.dsf.bpe.PingProcessPluginDefinition;
+
+public class VersionUtils
+{
+ public static String appendFhirResourceVersion(String toAppend)
+ {
+ return toAppend + "|" + getFhirResourceVersion();
+ }
+
+ public static String getFhirResourceVersion()
+ {
+ return new PingProcessPluginDefinition().getVersion().substring(0, 3);
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/logging/PingPongLogger.java b/src/main/java/dev/dsf/bpe/util/logging/PingPongLogger.java
new file mode 100644
index 00000000..e7cf5cdb
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/logging/PingPongLogger.java
@@ -0,0 +1,42 @@
+package dev.dsf.bpe.util.logging;
+
+import org.hl7.fhir.r4.model.Task;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class PingPongLogger
+{
+ private final Logger logger;
+ private Task task;
+
+ public PingPongLogger(Class> clazz, Task task)
+ {
+ this.logger = LoggerFactory.getLogger(clazz);
+ this.task = task;
+ }
+
+ public void info(String message, Object... args)
+ {
+ logger.info(prependProcessInfo(message), args);
+ }
+
+ public void warn(String message, Object... args)
+ {
+ logger.warn(prependProcessInfo(message), args);
+ }
+
+ public void error(String message, Object... args)
+ {
+ logger.error(prependProcessInfo(message), args);
+ }
+
+ public void debug(String message, Object... args)
+ {
+ logger.debug(prependProcessInfo(message), args);
+ }
+
+ private String prependProcessInfo(String message)
+ {
+ return "Process for Task " + task.getIdElement().getValue() + ": " + message;
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/task/NetworkSpeedCalculator.java b/src/main/java/dev/dsf/bpe/util/task/NetworkSpeedCalculator.java
new file mode 100644
index 00000000..fe8389be
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/task/NetworkSpeedCalculator.java
@@ -0,0 +1,46 @@
+package dev.dsf.bpe.util.task;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+import dev.dsf.bpe.ConstantsPing;
+
+public class NetworkSpeedCalculator
+{
+ public static BigDecimal calculate(int bytes, long duration, String unit)
+ {
+ if (bytes == 0)
+ return BigDecimal.ZERO;
+ if (duration == 0)
+ return BigDecimal.valueOf(Long.MAX_VALUE);
+
+ BigDecimal seconds = BigDecimal.valueOf(duration).setScale(3, RoundingMode.HALF_UP)
+ .divide(BigDecimal.valueOf(1000).setScale(3, RoundingMode.HALF_UP), RoundingMode.HALF_UP);
+
+ return switch (unit)
+ {
+ case ConstantsPing.CODESYSTEM_DSF_PING_UNITS_VALUE_BITS_PER_SECOND ->
+ {
+ BigDecimal bits = new BigDecimal(bytes * 8L).setScale(3, RoundingMode.HALF_UP);
+ yield bits.divide(seconds, 2, RoundingMode.HALF_UP);
+ }
+ case ConstantsPing.CODESYSTEM_DSF_PING_UNITS_VALUE_MEGABITS_PER_SECOND ->
+ {
+ BigDecimal megabits = new BigDecimal(bytes * 8L).divide(BigDecimal.valueOf(1000000),
+ RoundingMode.HALF_UP);
+ yield megabits.divide(seconds, 2, RoundingMode.HALF_UP);
+ }
+ case ConstantsPing.CODESYSTEM_DSF_PING_UNITS_VALUE_BYTES_PER_SECOND ->
+ {
+ BigDecimal bytesLocal = new BigDecimal(bytes).setScale(3, RoundingMode.HALF_UP);
+ yield bytesLocal.divide(seconds, 2, RoundingMode.HALF_UP);
+ }
+ case ConstantsPing.CODESYSTEM_DSF_PING_UNITS_VALUE_MEGABYTES_PER_SECOND ->
+ {
+ BigDecimal megabytes = new BigDecimal(bytes).divide(BigDecimal.valueOf(1000000), RoundingMode.HALF_UP);
+ yield megabytes.divide(seconds, 2, RoundingMode.HALF_UP);
+ }
+ default -> BigDecimal.ZERO;
+ };
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/task/input/generator/DownloadResourceReferenceGenerator.java b/src/main/java/dev/dsf/bpe/util/task/input/generator/DownloadResourceReferenceGenerator.java
new file mode 100644
index 00000000..0857e824
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/task/input/generator/DownloadResourceReferenceGenerator.java
@@ -0,0 +1,25 @@
+package dev.dsf.bpe.util.task.input.generator;
+
+import org.hl7.fhir.r4.model.Coding;
+import org.hl7.fhir.r4.model.Reference;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+
+public class DownloadResourceReferenceGenerator
+{
+ public static Task.ParameterComponent create(String uri)
+ {
+ Reference reference = new Reference(uri);
+ reference.setType("Binary");
+ return create(reference);
+ }
+
+ public static Task.ParameterComponent create(Reference reference)
+ {
+ Task.ParameterComponent param = new Task.ParameterComponent();
+ param.setValue(reference).getType().addCoding(new Coding(ConstantsPing.CODESYSTEM_DSF_PING,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOAD_RESOURCE_REFERENCE, null));
+ return param;
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/task/input/generator/DownloadResourceSizeGenerator.java b/src/main/java/dev/dsf/bpe/util/task/input/generator/DownloadResourceSizeGenerator.java
new file mode 100644
index 00000000..8071fc20
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/task/input/generator/DownloadResourceSizeGenerator.java
@@ -0,0 +1,18 @@
+package dev.dsf.bpe.util.task.input.generator;
+
+import org.hl7.fhir.r4.model.Coding;
+import org.hl7.fhir.r4.model.IntegerType;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+
+public class DownloadResourceSizeGenerator
+{
+ public static Task.ParameterComponent create(int sizeBytes)
+ {
+ Task.ParameterComponent param = new Task.ParameterComponent();
+ param.setValue(new IntegerType(sizeBytes)).getType().addCoding(new Coding(ConstantsPing.CODESYSTEM_DSF_PING,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOAD_RESOURCE_SIZE_BYTES, null));
+ return param;
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/task/input/generator/DownloadedBytesGenerator.java b/src/main/java/dev/dsf/bpe/util/task/input/generator/DownloadedBytesGenerator.java
new file mode 100644
index 00000000..e75d0705
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/task/input/generator/DownloadedBytesGenerator.java
@@ -0,0 +1,17 @@
+package dev.dsf.bpe.util.task.input.generator;
+
+import org.hl7.fhir.r4.model.IntegerType;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+
+public class DownloadedBytesGenerator
+{
+ public static Task.ParameterComponent create(int bytes)
+ {
+ Task.ParameterComponent param = new Task.ParameterComponent();
+ param.setValue(new IntegerType(bytes)).getType().addCoding().setSystem(ConstantsPing.CODESYSTEM_DSF_PING)
+ .setCode(ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOADED_BYTES);
+ return param;
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/task/input/generator/DownloadedDurationMillisGenerator.java b/src/main/java/dev/dsf/bpe/util/task/input/generator/DownloadedDurationMillisGenerator.java
new file mode 100644
index 00000000..313155c3
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/task/input/generator/DownloadedDurationMillisGenerator.java
@@ -0,0 +1,18 @@
+package dev.dsf.bpe.util.task.input.generator;
+
+import org.hl7.fhir.r4.model.DecimalType;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+
+public class DownloadedDurationMillisGenerator
+{
+ public static Task.ParameterComponent create(long durationMillis)
+ {
+ Task.ParameterComponent param = new Task.ParameterComponent();
+ param.setValue(new DecimalType(durationMillis)).getType().addCoding()
+ .setSystem(ConstantsPing.CODESYSTEM_DSF_PING)
+ .setCode(ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOADED_DURATION_MILLIS);
+ return param;
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/task/input/generator/ErrorMessageGenerator.java b/src/main/java/dev/dsf/bpe/util/task/input/generator/ErrorMessageGenerator.java
new file mode 100644
index 00000000..d7c62b67
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/task/input/generator/ErrorMessageGenerator.java
@@ -0,0 +1,27 @@
+package dev.dsf.bpe.util.task.input.generator;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+
+public class ErrorMessageGenerator
+{
+ public static List create(List errorMessages)
+ {
+ if (errorMessages == null || errorMessages.isEmpty())
+ return List.of();
+ return errorMessages.stream().map(ErrorMessageGenerator::create).collect(Collectors.toList());
+ }
+
+ public static Task.ParameterComponent create(String errorMessage)
+ {
+ Task.ParameterComponent param = new Task.ParameterComponent();
+ param.setValue(new StringType(errorMessage)).getType().addCoding().setSystem(ConstantsPing.CODESYSTEM_DSF_PING)
+ .setCode(ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_ERROR_MESSAGE);
+ return param;
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/task/input/generator/NetworkSpeedMetricGenerator.java b/src/main/java/dev/dsf/bpe/util/task/input/generator/NetworkSpeedMetricGenerator.java
new file mode 100644
index 00000000..b1d33761
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/task/input/generator/NetworkSpeedMetricGenerator.java
@@ -0,0 +1,28 @@
+package dev.dsf.bpe.util.task.input.generator;
+
+import org.hl7.fhir.r4.model.Coding;
+import org.hl7.fhir.r4.model.DecimalType;
+import org.hl7.fhir.r4.model.IntegerType;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+
+public class NetworkSpeedMetricGenerator
+{
+ public static Task.ParameterComponent createDownloadedDurationMillis(long duration)
+ {
+ Task.ParameterComponent downloadedDuration = new Task.ParameterComponent();
+ downloadedDuration.setValue(new DecimalType(duration)).getType()
+ .addCoding(new Coding(ConstantsPing.CODESYSTEM_DSF_PING,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOADED_DURATION_MILLIS, null));
+ return downloadedDuration;
+ }
+
+ public static Task.ParameterComponent createDownloadedBytes(int bytes)
+ {
+ Task.ParameterComponent downloadedBytes = new Task.ParameterComponent();
+ downloadedBytes.setValue(new IntegerType(bytes)).getType().addCoding(new Coding(
+ ConstantsPing.CODESYSTEM_DSF_PING, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOADED_BYTES, null));
+ return downloadedBytes;
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/task/output/generator/ErrorMessageGenerator.java b/src/main/java/dev/dsf/bpe/util/task/output/generator/ErrorMessageGenerator.java
new file mode 100644
index 00000000..ab34226b
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/task/output/generator/ErrorMessageGenerator.java
@@ -0,0 +1,27 @@
+package dev.dsf.bpe.util.task.output.generator;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.hl7.fhir.r4.model.StringType;
+import org.hl7.fhir.r4.model.Task;
+
+import dev.dsf.bpe.ConstantsPing;
+
+public class ErrorMessageGenerator
+{
+ public static List create(List errorMessages)
+ {
+ if (errorMessages == null || errorMessages.isEmpty())
+ return List.of();
+ return errorMessages.stream().map(ErrorMessageGenerator::create).collect(Collectors.toList());
+ }
+
+ public static Task.TaskOutputComponent create(String errorMessage)
+ {
+ Task.TaskOutputComponent param = new Task.TaskOutputComponent();
+ param.setValue(new StringType(errorMessage)).getType().addCoding().setSystem(ConstantsPing.CODESYSTEM_DSF_PING)
+ .setCode(ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_ERROR_MESSAGE);
+ return param;
+ }
+}
diff --git a/src/main/java/dev/dsf/bpe/util/task/output/generator/PingStatusGenerator.java b/src/main/java/dev/dsf/bpe/util/task/output/generator/PingStatusGenerator.java
new file mode 100644
index 00000000..8cd25bfc
--- /dev/null
+++ b/src/main/java/dev/dsf/bpe/util/task/output/generator/PingStatusGenerator.java
@@ -0,0 +1,1008 @@
+package dev.dsf.bpe.util.task.output.generator;
+
+import static dev.dsf.bpe.util.VersionUtils.appendFhirResourceVersion;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import org.hl7.fhir.r4.model.Coding;
+import org.hl7.fhir.r4.model.DecimalType;
+import org.hl7.fhir.r4.model.Extension;
+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.Type;
+
+import dev.dsf.bpe.ConstantsPing;
+import dev.dsf.bpe.v1.constants.NamingSystems.EndpointIdentifier;
+import dev.dsf.bpe.v1.constants.NamingSystems.OrganizationIdentifier;
+import dev.dsf.bpe.v1.variables.Target;
+
+public class PingStatusGenerator
+{
+ public static Task updatePingStatusOutput(Task task, String correlationKey, List errorMessages)
+ {
+ List outputs = filterByCorrelationKey(
+ getOutputsByExtensionUrlAndCodes(task, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PING_STATUS),
+ correlationKey);
+
+ if (outputs.isEmpty())
+ {
+ task.addOutput(updateStatusOutput(new TaskOutputComponent(), errorMessages));
+ }
+ else
+ {
+ if (outputs.size() == 1)
+ {
+ updateStatusOutput(outputs.get(0), errorMessages);
+ }
+ else
+ {
+ throw new RuntimeException("There is more than one ping/pong status output for task " + task.getId()
+ + " with correlation key " + correlationKey);
+ }
+ }
+ return task;
+ }
+
+ public static Task updatePongStatusOutput(Task task, List errorMessages)
+ {
+ List pongStatusOutputs = getOutputsByExtensionUrlAndCodes(task,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PONG_STATUS);
+ if (pongStatusOutputs.isEmpty())
+ {
+ task.addOutput(updateStatusOutput(new TaskOutputComponent(), errorMessages));
+ }
+ else
+ {
+ if (pongStatusOutputs.size() == 1)
+ {
+ updateStatusOutput(pongStatusOutputs.get(0), errorMessages);
+ }
+ else
+ {
+ throw new RuntimeException("There is more than one pong status output for task " + task.getId());
+ }
+ }
+
+ return task;
+ }
+
+ public static TaskOutputComponent updateStatusOutput(TaskOutputComponent output, List errorMessages)
+ {
+ if (output != null)
+ {
+ Extension pingStatusExtension = getOrCreatePingStatusExtension(output);
+ List errorMessageExtensions = pingStatusExtension.getExtension().stream()
+ .filter(extension -> ConstantsPing.EXTENSION_URL_ERROR_MESSAGE.equals(extension.getUrl())).toList();
+ if (errorMessageExtensions.isEmpty())
+ {
+ addErrorMessages(output, errorMessages);
+ }
+ else
+ {
+ Set existingErrors = errorMessageExtensions.stream()
+ .map(extension -> ((StringType) extension.getValue()).getValue()).collect(Collectors.toSet());
+ existingErrors.addAll(errorMessages);
+ List nonErrorMessageExtensions = pingStatusExtension.getExtension().stream()
+ .filter(extension -> !ConstantsPing.EXTENSION_URL_ERROR_MESSAGE.equals(extension.getUrl()))
+ .toList();
+ List updatedErrorMessageExtensions = existingErrors.stream()
+ .map(errorMessage -> new Extension().setUrl(ConstantsPing.EXTENSION_URL_ERROR_MESSAGE)
+ .setValue(new StringType(errorMessage)))
+ .collect(Collectors.toCollection(ArrayList::new));
+ updatedErrorMessageExtensions.addAll(nonErrorMessageExtensions);
+ pingStatusExtension.setExtension(updatedErrorMessageExtensions);
+ }
+ }
+
+ return output;
+ }
+
+ public static Task updatePingStatusOutput(Task task, String correlationKey, String statusCode)
+ {
+ List pingStatusOutputs = filterByCorrelationKey(
+ getOutputsByExtensionUrlAndCodes(task, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PING_STATUS),
+ correlationKey);
+ if (pingStatusOutputs.isEmpty())
+ {
+ task.addOutput(updatePingStatusOutput(new TaskOutputComponent(), statusCode));
+ }
+ else
+ {
+ if (pingStatusOutputs.size() == 1)
+ {
+ updatePingStatusOutput(pingStatusOutputs.get(0), statusCode);
+ }
+ else
+ {
+ throw new RuntimeException("There is more than one ping status output for task " + task.getId()
+ + " with correlation key " + correlationKey);
+ }
+ }
+
+ return task;
+ }
+
+ public static TaskOutputComponent updatePingStatusOutput(TaskOutputComponent outputComponent, String statusCode)
+ {
+ if (hasStatusCodeSet(outputComponent))
+ {
+ updateStatus(outputComponent, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PING_STATUS, statusCode);
+ }
+ else
+ {
+ addStatus(outputComponent, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PING_STATUS, statusCode);
+ }
+
+ return outputComponent;
+ }
+
+ public static Task updatePongStatusOutput(Task task, String statusCode)
+ {
+ List pongStatusOutputs = getOutputsByExtensionUrlAndCodes(task,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PONG_STATUS);
+ if (pongStatusOutputs.isEmpty())
+ {
+ task.addOutput(updatePongStatusOutput(new TaskOutputComponent(), statusCode));
+ }
+ else
+ {
+ if (pongStatusOutputs.size() == 1)
+ {
+ updatePongStatusOutput(pongStatusOutputs.get(0), statusCode);
+ }
+ else
+ {
+ throw new RuntimeException("There is more than one pong status output for task " + task.getId());
+ }
+ }
+
+ return task;
+ }
+
+ public static TaskOutputComponent updatePongStatusOutput(TaskOutputComponent outputComponent, String statusCode)
+ {
+ if (hasStatusCodeSet(outputComponent))
+ {
+ updateStatus(outputComponent, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PONG_STATUS, statusCode);
+ }
+ else
+ {
+ addStatus(outputComponent, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PONG_STATUS, statusCode);
+ }
+
+ return outputComponent;
+ }
+
+ public static Task updatePingStatusOutput(Task task, Target target)
+ {
+ List outputs = filterByCorrelationKey(
+ getOutputsByExtensionUrlAndCodes(task, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PING_STATUS),
+ target.getCorrelationKey());
+ if (outputs.isEmpty())
+ {
+ task.addOutput(updateStatusOutput(new TaskOutputComponent(), target));
+ }
+ else
+ {
+ if (outputs.size() == 1)
+ {
+ updateStatusOutput(outputs.get(0), target);
+ }
+ else
+ {
+ throw new RuntimeException("There is more than one ping/pong status output for task " + task.getId()
+ + " with correlation key " + target.getCorrelationKey());
+ }
+ }
+ return task;
+ }
+
+ public static Task updatePongStatusOutput(Task task, Target target)
+ {
+ List outputs = getOutputsByExtensionUrlAndCodes(task,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PONG_STATUS);
+ if (outputs.isEmpty())
+ {
+ task.addOutput(updateStatusOutput(new TaskOutputComponent(), target));
+ }
+ else
+ {
+ if (outputs.size() == 1)
+ {
+ updateStatusOutput(outputs.get(0), target);
+ }
+ else
+ {
+ throw new RuntimeException("There is more than one pong status output for task " + task.getId());
+ }
+ }
+
+ return task;
+ }
+
+ public static TaskOutputComponent updateStatusOutput(TaskOutputComponent outputComponent, Target target)
+ {
+ if (hasTargetSet(outputComponent))
+ {
+ updateTarget(outputComponent, target);
+ }
+ else
+ {
+ addTarget(outputComponent, target);
+ }
+ return outputComponent;
+ }
+
+ public static Task updatePingStatusOutput(Task task, String correlationKey, BigDecimal downloadSpeed,
+ BigDecimal uploadSpeed, String statusCode)
+ {
+ List outputs = filterByCorrelationKey(
+ getOutputsByExtensionUrlAndCodes(task, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PING_STATUS),
+ correlationKey);
+ if (outputs.isEmpty())
+ {
+ task.addOutput(updateStatusOutput(new TaskOutputComponent(), downloadSpeed, uploadSpeed, statusCode));
+ }
+ else
+ {
+ if (outputs.size() == 1)
+ {
+ updateStatusOutput(outputs.get(0), downloadSpeed, uploadSpeed, statusCode);
+ }
+ else
+ {
+ throw new RuntimeException("There is more than one ping/pong status output for task " + task.getId()
+ + " with correlation key " + correlationKey);
+ }
+ }
+ return task;
+ }
+
+ public static Task updatePongStatusOutput(Task task, BigDecimal downloadSpeed, BigDecimal uploadSpeed,
+ String statusCode)
+ {
+ List outputs = getOutputsByExtensionUrlAndCodes(task,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PONG_STATUS);
+ if (outputs.isEmpty())
+ {
+ task.addOutput(updateStatusOutput(new TaskOutputComponent(), downloadSpeed, uploadSpeed, statusCode));
+ }
+ else
+ {
+ if (outputs.size() == 1)
+ {
+ updateStatusOutput(outputs.get(0), downloadSpeed, uploadSpeed, statusCode);
+ }
+ else
+ {
+ throw new RuntimeException("There is more than one ping/pong status output for task " + task.getId());
+ }
+ }
+
+ return task;
+ }
+
+ public static TaskOutputComponent updateStatusOutput(TaskOutputComponent outputComponent, BigDecimal downloadSpeed,
+ BigDecimal uploadSpeed, String networkSpeedUnit)
+ {
+ if (hasDownloadSpeedSet(outputComponent))
+ {
+ updateDownloadSpeed(outputComponent, downloadSpeed, networkSpeedUnit);
+ }
+ else
+ {
+ addDownloadSpeed(outputComponent, downloadSpeed, networkSpeedUnit);
+ }
+
+ if (hasUploadSpeedSet(outputComponent))
+ {
+ updateUploadSpeed(outputComponent, uploadSpeed, networkSpeedUnit);
+ }
+ else
+ {
+ addUploadSpeed(outputComponent, uploadSpeed, networkSpeedUnit);
+ }
+
+ return outputComponent;
+ }
+
+ public static Task updatePingStatusOutputDownloadSpeed(Task task, String correlationKey, BigDecimal downloadSpeed,
+ String networkSpeedUnit)
+ {
+ List outputs = filterByCorrelationKey(
+ getOutputsByExtensionUrlAndCodes(task, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PING_STATUS),
+ correlationKey);
+ if (outputs.isEmpty())
+ {
+ task.addOutput(updateStatusOutputDownloadSpeed(new TaskOutputComponent(), downloadSpeed, networkSpeedUnit));
+ }
+ else
+ {
+ if (outputs.size() == 1)
+ {
+ updateStatusOutputDownloadSpeed(outputs.get(0), downloadSpeed, networkSpeedUnit);
+ }
+ else
+ {
+ throw new RuntimeException("There is more than one ping/pong status output for task " + task.getId()
+ + " with correlation key " + correlationKey);
+ }
+ }
+ return task;
+ }
+
+ public static Task updatePongStatusOutputDownloadSpeed(Task task, BigDecimal downloadSpeed, String networkSpeedUnit)
+ {
+ List outputs = getOutputsByExtensionUrlAndCodes(task,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PONG_STATUS);
+ if (outputs.isEmpty())
+ {
+ task.addOutput(updateStatusOutputDownloadSpeed(new TaskOutputComponent(), downloadSpeed, networkSpeedUnit));
+ }
+ else
+ {
+ if (outputs.size() == 1)
+ {
+ updateStatusOutputDownloadSpeed(outputs.get(0), downloadSpeed, networkSpeedUnit);
+ }
+ else
+ {
+ throw new RuntimeException("There is more than one ping/pong status output for task " + task.getId());
+ }
+ }
+
+ return task;
+ }
+
+ public static TaskOutputComponent updateStatusOutputDownloadSpeed(TaskOutputComponent outputComponent,
+ BigDecimal downloadSpeed, String networkSpeedUnit)
+ {
+ if (hasDownloadSpeedSet(outputComponent))
+ {
+ updateDownloadSpeed(outputComponent, downloadSpeed, networkSpeedUnit);
+ }
+ else
+ {
+ addDownloadSpeed(outputComponent, downloadSpeed, networkSpeedUnit);
+ }
+
+ return outputComponent;
+ }
+
+ public static Task updatePingStatusOutputUploadSpeed(Task task, String correlationKey, BigDecimal uploadSpeed,
+ String networkSpeedUnit)
+ {
+ List outputs = filterByCorrelationKey(
+ getOutputsByExtensionUrlAndCodes(task, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PING_STATUS),
+ correlationKey);
+ if (outputs.isEmpty())
+ {
+ task.addOutput(updateStatusOutputUploadSpeed(new TaskOutputComponent(), uploadSpeed, networkSpeedUnit));
+ }
+ else
+ {
+ if (outputs.size() == 1)
+ {
+ updateStatusOutputUploadSpeed(outputs.get(0), uploadSpeed, networkSpeedUnit);
+ }
+ else
+ {
+ throw new RuntimeException("There is more than one ping/pong status output for task " + task.getId()
+ + " with correlation key " + correlationKey);
+ }
+ }
+
+ return task;
+ }
+
+ public static Task updatePongStatusOutputUploadSpeed(Task task, BigDecimal uploadSpeed, String networkSpeedUnit)
+ {
+ List outputs = getOutputsByExtensionUrlAndCodes(task,
+ ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PONG_STATUS);
+ if (outputs.isEmpty())
+ {
+ task.addOutput(updateStatusOutputUploadSpeed(new TaskOutputComponent(), uploadSpeed, networkSpeedUnit));
+ }
+ else
+ {
+ if (outputs.size() == 1)
+ {
+ updateStatusOutputUploadSpeed(outputs.get(0), uploadSpeed, networkSpeedUnit);
+ }
+ else
+ {
+ throw new RuntimeException("There is more than one ping/pong status output for task " + task.getId());
+ }
+ }
+
+ return task;
+ }
+
+ public static TaskOutputComponent updateStatusOutputUploadSpeed(TaskOutputComponent outputComponent,
+ BigDecimal uploadSpeed, String networkSpeedUnit)
+ {
+ if (hasDownloadSpeedSet(outputComponent))
+ {
+ updateUploadSpeed(outputComponent, uploadSpeed, networkSpeedUnit);
+ }
+ else
+ {
+ addUploadSpeed(outputComponent, uploadSpeed, networkSpeedUnit);
+ }
+
+ return outputComponent;
+ }
+
+ private static boolean hasTargetSet(TaskOutputComponent outputComponent)
+ {
+ List correlationKeyExtensions = outputComponent
+ .getExtensionsByUrl(ConstantsPing.EXTENSION_URL_CORRELATION_KEY);
+ List organizationIdentifierExtensions = outputComponent
+ .getExtensionsByUrl(ConstantsPing.EXTENSION_URL_ORGANIZATION_IDENTIFIER);
+ List endpointIdentifierExtensions = outputComponent
+ .getExtensionsByUrl(ConstantsPing.EXTENSION_URL_ENDPOINT_IDENTIFIER);
+ return !correlationKeyExtensions.isEmpty() || !organizationIdentifierExtensions.isEmpty()
+ || !endpointIdentifierExtensions.isEmpty();
+ }
+
+ private static boolean hasStatusCodeSet(TaskOutputComponent outputComponent)
+ {
+ Type valueType = outputComponent.getValue();
+ List outputTypeCodings = outputComponent.getType().getCoding();
+
+ return (valueType instanceof Coding coding
+ && ConstantsPing.CODESYSTEM_DSF_PING_STATUS.equals(coding.getSystem()))
+ || outputTypeCodings.stream()
+ .anyMatch(coding -> ConstantsPing.CODESYSTEM_DSF_PING.equals(coding.getSystem()));
+ }
+
+ private static boolean hasNetworkSpeedSet(TaskOutputComponent outputComponent)
+ {
+ return hasDownloadSpeedSet(outputComponent) && hasUploadSpeedSet(outputComponent);
+ }
+
+ private static boolean hasDownloadSpeedSet(TaskOutputComponent outputComponent)
+ {
+ Extension extension = getOrCreatePingStatusExtension(outputComponent);
+ Extension downloadSpeedExtension = extension.getExtensionByUrl(ConstantsPing.EXTENSION_URL_DOWNLOAD_SPEED);
+
+ return downloadSpeedExtension != null;
+ }
+
+ private static boolean hasUploadSpeedSet(TaskOutputComponent outputComponent)
+ {
+ Extension extension = getOrCreatePingStatusExtension(outputComponent);
+ Extension uploadSpeedExtension = extension.getExtensionByUrl(ConstantsPing.EXTENSION_URL_UPLOAD_SPEED);
+
+ return uploadSpeedExtension != null;
+ }
+
+ public static TaskOutputComponent createPingStatusOutput(Target target, String statusCode)
+ {
+ return createPingStatusOutput(target, statusCode, null);
+ }
+
+ public static TaskOutputComponent createPingStatusOutput(Target target, String statusCode, BigDecimal downloadSpeed,
+ BigDecimal uploadSpeed, String unit)
+ {
+ return createPingStatusOutput(target, statusCode, null, downloadSpeed, uploadSpeed, unit);
+ }
+
+ public static TaskOutputComponent createPingStatusOutput(Target target, String statusCode,
+ List errorMessages)
+ {
+ return createStatusOutput(target, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PING_STATUS, statusCode,
+ errorMessages, null, null, null);
+ }
+
+ public static TaskOutputComponent createPingStatusOutput(Target target, String statusCode,
+ List errorMessages, BigDecimal downloadSpeed, BigDecimal uploadSpeed, String unit)
+ {
+ return createStatusOutput(target, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PING_STATUS, statusCode,
+ errorMessages, downloadSpeed, uploadSpeed, unit);
+ }
+
+ public static TaskOutputComponent createPongStatusOutput(Target target, String statusCode)
+ {
+ return createPongStatusOutput(target, statusCode, null);
+ }
+
+ public static TaskOutputComponent createPongStatusOutput(Target target, String statusCode, BigDecimal downloadSpeed,
+ BigDecimal uploadSpeed, String unit)
+ {
+ return createPongStatusOutput(target, statusCode, null, downloadSpeed, uploadSpeed, unit);
+ }
+
+ public static TaskOutputComponent createPongStatusOutput(Target target, String statusCode,
+ List errorMessages)
+ {
+ return createStatusOutput(target, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PONG_STATUS, statusCode,
+ errorMessages, null, null, null);
+ }
+
+ public static TaskOutputComponent createPongStatusOutput(Target target, String statusCode,
+ List errorMessages, BigDecimal downloadSpeed, BigDecimal uploadSpeed, String unit)
+ {
+ return createStatusOutput(target, ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PONG_STATUS, statusCode,
+ errorMessages, downloadSpeed, uploadSpeed, unit);
+ }
+
+ private static TaskOutputComponent createStatusOutput(Target target, String outputParameter, String statusCode,
+ List errorMessages, BigDecimal downloadSpeed, BigDecimal uploadSpeed, String unit)
+ {
+ TaskOutputComponent output = new TaskOutputComponent();
+ addStatus(output, outputParameter, statusCode);
+ addTarget(output, target);
+ addErrorMessages(output, errorMessages);
+ addNetworkSpeed(output, downloadSpeed, uploadSpeed, unit);
+
+ return output;
+ }
+
+ private static TaskOutputComponent addStatus(TaskOutputComponent outputComponent, String outputParameter,
+ String statusCode)
+ {
+ if (outputParameter != null && statusCode != null)
+ {
+ outputComponent
+ .setValue(new Coding().setSystem(ConstantsPing.CODESYSTEM_DSF_PING_STATUS).setCode(statusCode));
+ outputComponent.getType().addCoding().setSystem(ConstantsPing.CODESYSTEM_DSF_PING).setCode(outputParameter);
+ sortStatusOutputExtensions(outputComponent);
+ }
+
+ return outputComponent;
+ }
+
+ private static TaskOutputComponent updateStatus(TaskOutputComponent outputComponent, String outputParameter,
+ String statusCode)
+ {
+ Type valueType = outputComponent.getValue();
+ if (valueType instanceof Coding coding)
+ {
+ coding.setSystem(ConstantsPing.CODESYSTEM_DSF_PING_STATUS).setCode(statusCode);
+ }
+ else
+ {
+ outputComponent
+ .setValue(new Coding().setSystem(ConstantsPing.CODESYSTEM_DSF_PING_STATUS).setCode(statusCode));
+ }
+
+ List outputTypeCodings = outputComponent.getType().getCoding();
+ if (outputTypeCodings.isEmpty())
+ {
+ outputComponent.getType().addCoding().setSystem(ConstantsPing.CODESYSTEM_DSF_PING).setCode(outputParameter);
+ }
+ else
+ {
+ if (outputTypeCodings.size() == 1)
+ {
+ Coding coding = outputTypeCodings.get(0);
+ coding.setSystem(ConstantsPing.CODESYSTEM_DSF_PING).setCode(outputParameter);
+ }
+ else
+ {
+ outputComponent.getType().setCoding(null);
+ outputComponent.getType().addCoding().setSystem(ConstantsPing.CODESYSTEM_DSF_PING)
+ .setCode(outputParameter);
+ }
+ }
+ sortStatusOutputExtensions(outputComponent);
+
+ return outputComponent;
+ }
+
+ private static TaskOutputComponent addTarget(TaskOutputComponent outputComponent, Target target)
+ {
+ if (target != null)
+ {
+ Extension extension = getOrCreatePingStatusExtension(outputComponent);
+
+ extension.addExtension(ConstantsPing.EXTENSION_URL_CORRELATION_KEY,
+ new StringType(target.getCorrelationKey()));
+ extension.addExtension().setUrl(ConstantsPing.EXTENSION_URL_ORGANIZATION_IDENTIFIER)
+ .setValue(OrganizationIdentifier.withValue(target.getOrganizationIdentifierValue()));
+ extension.addExtension().setUrl(ConstantsPing.EXTENSION_URL_ENDPOINT_IDENTIFIER)
+ .setValue(EndpointIdentifier.withValue(target.getEndpointIdentifierValue()));
+ sortStatusOutputExtensions(outputComponent);
+ }
+
+ return outputComponent;
+ }
+
+ private static TaskOutputComponent updateTarget(TaskOutputComponent outputComponent, Target target)
+ {
+ Extension extension = getOrCreatePingStatusExtension(outputComponent);
+
+ Extension correlationKeyExtension = extension.getExtensionByUrl(ConstantsPing.EXTENSION_URL_CORRELATION_KEY);
+ if (correlationKeyExtension != null)
+ {
+ correlationKeyExtension.setValue(new StringType(target.getCorrelationKey()));
+ }
+ else
+ {
+ extension.addExtension(ConstantsPing.EXTENSION_URL_CORRELATION_KEY,
+ new StringType(target.getCorrelationKey()));
+ }
+
+ Extension organizationIdentifierExtension = extension
+ .getExtensionByUrl(ConstantsPing.EXTENSION_URL_ORGANIZATION_IDENTIFIER);
+ if (organizationIdentifierExtension != null)
+ {
+ organizationIdentifierExtension.setValue(new StringType(target.getOrganizationIdentifierValue()));
+ }
+ else
+ {
+ extension.addExtension().setUrl(ConstantsPing.EXTENSION_URL_ORGANIZATION_IDENTIFIER)
+ .setValue(OrganizationIdentifier.withValue(target.getOrganizationIdentifierValue()));
+ }
+
+ Extension urlEndpointIdentifier = extension.getExtensionByUrl(ConstantsPing.EXTENSION_URL_ENDPOINT_IDENTIFIER);
+ if (urlEndpointIdentifier != null)
+ {
+ urlEndpointIdentifier.setValue(new StringType(target.getEndpointIdentifierValue()));
+ }
+ else
+ {
+ extension.addExtension().setUrl(ConstantsPing.EXTENSION_URL_ENDPOINT_IDENTIFIER)
+ .setValue(EndpointIdentifier.withValue(target.getEndpointIdentifierValue()));
+ }
+ sortStatusOutputExtensions(outputComponent);
+
+ return outputComponent;
+ }
+
+ private static TaskOutputComponent addErrorMessages(TaskOutputComponent outputComponent, List errorMessages)
+ {
+ if (errorMessages != null)
+ {
+ Extension extension = getOrCreatePingStatusExtension(outputComponent);
+ for (String errorMessage : errorMessages)
+ {
+ extension.addExtension().setUrl(ConstantsPing.EXTENSION_URL_ERROR_MESSAGE)
+ .setValue(new StringType(errorMessage));
+ }
+ }
+ sortStatusOutputExtensions(outputComponent);
+ return outputComponent;
+ }
+
+ private static TaskOutputComponent updateErrorMessages(TaskOutputComponent outputComponent,
+ List errorMessages)
+ {
+ Extension extension = getOrCreatePingStatusExtension(outputComponent);
+ List nonErrorExtensions = extension.getExtension().stream()
+ .filter(extension1 -> !ConstantsPing.EXTENSION_URL_ERROR_MESSAGE.equals(extension1.getUrl()))
+ .collect(Collectors.toCollection(ArrayList::new));
+
+ if (errorMessages != null)
+ {
+ List newErrorExtensions = errorMessages.stream()
+ .map(errorMessage -> new Extension(ConstantsPing.EXTENSION_URL_ERROR_MESSAGE,
+ new StringType(errorMessage)))
+ .collect(Collectors.toCollection(ArrayList::new));
+ nonErrorExtensions.addAll(newErrorExtensions);
+ extension.setExtension(newErrorExtensions);
+ }
+ else
+ {
+ extension.setExtension(nonErrorExtensions);
+ }
+ sortStatusOutputExtensions(outputComponent);
+
+ return outputComponent;
+ }
+
+ private static TaskOutputComponent addNetworkSpeed(TaskOutputComponent outputComponent, BigDecimal downloadSpeed,
+ BigDecimal uploadSpeed, String unit)
+ {
+ addDownloadSpeed(outputComponent, downloadSpeed, unit);
+ addUploadSpeed(outputComponent, uploadSpeed, unit);
+
+ return outputComponent;
+ }
+
+ private static TaskOutputComponent updateNetworkSpeed(TaskOutputComponent outputComponent, BigDecimal downloadSpeed,
+ BigDecimal uploadSpeed, String unit)
+ {
+ updateDownloadSpeed(outputComponent, downloadSpeed, unit);
+ updateUploadSpeed(outputComponent, uploadSpeed, unit);
+ return outputComponent;
+ }
+
+ private static TaskOutputComponent addDownloadSpeed(TaskOutputComponent outputComponent, BigDecimal downloadSpeed,
+ String unit)
+ {
+ if (downloadSpeed != null && unit != null)
+ {
+ Extension extension = getOrCreatePingStatusExtension(outputComponent);
+ Extension downloadSpeedExtension = extension.addExtension()
+ .setUrl(ConstantsPing.EXTENSION_URL_DOWNLOAD_SPEED);
+ Extension networkSpeed = downloadSpeedExtension.addExtension()
+ .setUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED);
+ networkSpeed.addExtension().setUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED_VALUE)
+ .setValue(new DecimalType(downloadSpeed));
+ networkSpeed.addExtension().setUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED_UNIT)
+ .setValue(new Coding(ConstantsPing.CODESYSTEM_DSF_PING_UNITS, unit, null));
+ }
+ sortStatusOutputExtensions(outputComponent);
+
+ return outputComponent;
+ }
+
+ private static TaskOutputComponent updateDownloadSpeed(TaskOutputComponent outputComponent,
+ BigDecimal downloadSpeed, String unit)
+ {
+ if (downloadSpeed != null && unit != null)
+ {
+ Extension extension = getOrCreatePingStatusExtension(outputComponent);
+ Extension downloadSpeedExtension = extension.getExtensionByUrl(ConstantsPing.EXTENSION_URL_DOWNLOAD_SPEED);
+ if (downloadSpeedExtension != null)
+ {
+ Extension networkSpeedExtension = downloadSpeedExtension
+ .getExtensionByUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED);
+ if (networkSpeedExtension != null)
+ {
+ networkSpeedExtension.setExtension(new ArrayList<>());
+ List extensions = networkSpeedExtension.getExtension();
+ extensions.add(new Extension(ConstantsPing.EXTENSION_URL_NETWORK_SPEED_VALUE,
+ new DecimalType(downloadSpeed)));
+ extensions.add(new Extension(ConstantsPing.EXTENSION_URL_NETWORK_SPEED_UNIT,
+ new Coding(ConstantsPing.CODESYSTEM_DSF_PING_UNITS, unit, null)));
+ }
+ }
+ else
+ {
+ downloadSpeedExtension = extension.addExtension().setUrl(ConstantsPing.EXTENSION_URL_DOWNLOAD_SPEED);
+ Extension networkSpeed = downloadSpeedExtension.addExtension()
+ .setUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED);
+ networkSpeed.addExtension().setUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED_VALUE)
+ .setValue(new DecimalType(downloadSpeed));
+ networkSpeed.addExtension().setUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED_UNIT)
+ .setValue(new Coding(ConstantsPing.CODESYSTEM_DSF_PING_UNITS, unit, null));
+ }
+ }
+ sortStatusOutputExtensions(outputComponent);
+
+ return outputComponent;
+ }
+
+ private static TaskOutputComponent addUploadSpeed(TaskOutputComponent outputComponent, BigDecimal uploadSpeed,
+ String unit)
+ {
+ if (uploadSpeed != null && unit != null)
+ {
+ Extension extension = getOrCreatePingStatusExtension(outputComponent);
+ Extension uploadSpeedExtension = extension.addExtension().setUrl(ConstantsPing.EXTENSION_URL_UPLOAD_SPEED);
+ Extension networkSpeed = uploadSpeedExtension.addExtension()
+ .setUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED);
+ networkSpeed.addExtension().setUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED_VALUE)
+ .setValue(new DecimalType(uploadSpeed));
+ networkSpeed.addExtension().setUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED_UNIT)
+ .setValue(new Coding(ConstantsPing.CODESYSTEM_DSF_PING_UNITS, unit, null));
+ }
+ sortStatusOutputExtensions(outputComponent);
+
+ return outputComponent;
+ }
+
+ private static TaskOutputComponent updateUploadSpeed(TaskOutputComponent outputComponent, BigDecimal uploadSpeed,
+ String unit)
+ {
+ if (uploadSpeed != null && unit != null)
+ {
+ Extension extension = getOrCreatePingStatusExtension(outputComponent);
+ Extension uploadSpeedExtension = extension.getExtensionByUrl(ConstantsPing.EXTENSION_URL_UPLOAD_SPEED);
+ if (uploadSpeedExtension != null)
+ {
+ Extension networkSpeedExtension = uploadSpeedExtension
+ .getExtensionByUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED);
+ if (networkSpeedExtension != null)
+ {
+ networkSpeedExtension.setExtension(new ArrayList<>());
+ List extensions = networkSpeedExtension.getExtension();
+ extensions.add(new Extension(ConstantsPing.EXTENSION_URL_NETWORK_SPEED_VALUE,
+ new DecimalType(uploadSpeed)));
+ extensions.add(new Extension(ConstantsPing.EXTENSION_URL_NETWORK_SPEED_UNIT,
+ new Coding(ConstantsPing.CODESYSTEM_DSF_PING_UNITS, unit, null)));
+ }
+ }
+ else
+ {
+ uploadSpeedExtension = extension.addExtension().setUrl(ConstantsPing.EXTENSION_URL_UPLOAD_SPEED);
+ Extension networkSpeed = uploadSpeedExtension.addExtension()
+ .setUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED);
+ networkSpeed.addExtension().setUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED_VALUE)
+ .setValue(new DecimalType(uploadSpeed));
+ networkSpeed.addExtension().setUrl(ConstantsPing.EXTENSION_URL_NETWORK_SPEED_UNIT)
+ .setValue(new Coding(ConstantsPing.CODESYSTEM_DSF_PING_UNITS, unit, null));
+ }
+ }
+ sortStatusOutputExtensions(outputComponent);
+
+ return outputComponent;
+ }
+
+ private static Extension getOrCreatePingStatusExtension(TaskOutputComponent outputComponent)
+ {
+ Optional optionalExtension = getPingStatusExtension(outputComponent);
+ if (optionalExtension.isPresent())
+ {
+ return optionalExtension.get();
+ }
+ else
+ {
+ Extension extension = outputComponent.addExtension();
+ extension.setUrl(appendFhirResourceVersion(ConstantsPing.EXTENSION_URL_PING_STATUS));
+ return extension;
+ }
+ }
+
+ private static Optional getPingStatusExtension(Task task)
+ {
+ Optional optPingStatusOutput = task.getOutput().stream()
+ .filter(outputComponent -> outputComponent.getExtension().stream()
+ .anyMatch(extension -> ConstantsPing.EXTENSION_URL_PING_STATUS.equals(extension.getUrl())))
+ .findFirst();
+ if (optPingStatusOutput.isPresent())
+ {
+ return getPingStatusExtension(optPingStatusOutput.get());
+ }
+ else
+ {
+ return Optional.empty();
+ }
+ }
+
+ private static Optional getPingStatusExtension(TaskOutputComponent outputComponent)
+ {
+ List pingStatusExtensions = outputComponent.getExtension().stream()
+ .filter(extension -> appendFhirResourceVersion(ConstantsPing.EXTENSION_URL_PING_STATUS)
+ .equals(extension.getUrl()))
+ .toList();
+ if (pingStatusExtensions.isEmpty())
+ {
+ return Optional.empty();
+ }
+ else
+ {
+ if (pingStatusExtensions.size() == 1)
+ {
+ return Optional.of(pingStatusExtensions.get(0));
+ }
+ else
+ {
+ throw new RuntimeException(
+ "Only one ping status extension is allowed but found " + pingStatusExtensions.size());
+ }
+ }
+ }
+
+ private static List getOutputsByExtensionUrlAndCodes(Task task, String... codes)
+ {
+ return task
+ .getOutput().stream().filter(
+ outputComponent -> outputComponent.getType().getCoding().stream()
+ .anyMatch(coding -> ConstantsPing.CODESYSTEM_DSF_PING.equals(coding.getSystem())
+ && Stream.of(codes).anyMatch(code -> code.equals(coding.getCode())))
+ || outputComponent.getExtension().stream()
+ .anyMatch(extension -> appendFhirResourceVersion(
+ ConstantsPing.EXTENSION_URL_PING_STATUS).equals(extension.getUrl())))
+ .collect(Collectors.toCollection(ArrayList::new));
+ }
+
+ private static List filterByCorrelationKey(List outputs,
+ String correlationKey)
+ {
+ return outputs.stream().filter(outputComponent ->
+ {
+ List outputExtensions = outputComponent.getExtension();
+ if (outputExtensions.isEmpty())
+ return false;
+ List pingStatusExtensions = outputExtensions.stream()
+ .filter(extension -> ConstantsPing.EXTENSION_URL_PING_STATUS.equals(extension.getUrl())).toList();
+ if (pingStatusExtensions.isEmpty())
+ return false;
+ List extensionsMatchingCorrelationKey = pingStatusExtensions.stream()
+ .filter(extension -> extension.getExtension().stream().anyMatch(
+ extension1 -> ConstantsPing.EXTENSION_URL_CORRELATION_KEY.equals(extension1.getUrl())
+ && correlationKey.equals(((StringType) extension1.getValue()).getValue())))
+ .toList();
+ if (extensionsMatchingCorrelationKey.isEmpty())
+ return false;
+ if (extensionsMatchingCorrelationKey.size() == 1)
+ {
+ return true;
+ }
+ else
+ {
+ throw new RuntimeException(
+ "Only one Task.output.extension.extension with correlationKey is allowed but found "
+ + extensionsMatchingCorrelationKey.size());
+ }
+ }).collect(Collectors.toCollection(ArrayList::new));
+ }
+
+ private static void sortStatusOutputExtensions(Task task)
+ {
+ List outputs = task.getOutput().stream()
+ .filter(outputComponent -> ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PING_STATUS
+ .equals(outputComponent.getType().getCodingFirstRep().getCode())
+ || ConstantsPing.CODESYSTEM_DSF_PING_VALUE_PONG_STATUS
+ .equals(outputComponent.getType().getCodingFirstRep().getCode()))
+ .toList();
+ outputs.forEach(PingStatusGenerator::sortStatusOutputExtensions);
+ }
+
+ private static void sortStatusOutputExtensions(TaskOutputComponent outputComponent)
+ {
+ Optional optPingStatusExtension = getPingStatusExtension(outputComponent);
+ if (optPingStatusExtension.isPresent())
+ {
+ Extension pingStatusExtension = optPingStatusExtension.get();
+ List extensions = pingStatusExtension.getExtension();
+ List sortedExtensions = new ArrayList<>();
+
+ // Extensions representing Target
+ Optional correlationKeyExtension = extensions.stream()
+ .filter(extension -> ConstantsPing.EXTENSION_URL_CORRELATION_KEY.equals(extension.getUrl()))
+ .findFirst();
+ Optional organizationIdentifierExtension = extensions.stream()
+ .filter(extension -> ConstantsPing.EXTENSION_URL_ORGANIZATION_IDENTIFIER.equals(extension.getUrl()))
+ .findFirst();
+ Optional endpointIdentifierExtension = extensions.stream()
+ .filter(extension -> ConstantsPing.EXTENSION_URL_ENDPOINT_IDENTIFIER.equals(extension.getUrl()))
+ .findFirst();
+ if (correlationKeyExtension.isPresent())
+ {
+ extensions.remove(correlationKeyExtension.get());
+ sortedExtensions.add(correlationKeyExtension.get());
+ }
+ if (organizationIdentifierExtension.isPresent())
+ {
+ extensions.remove(organizationIdentifierExtension.get());
+ sortedExtensions.add(organizationIdentifierExtension.get());
+ }
+ if (endpointIdentifierExtension.isPresent())
+ {
+ extensions.remove(endpointIdentifierExtension.get());
+ sortedExtensions.add(endpointIdentifierExtension.get());
+ }
+
+ Optional downloadSpeedExtension = extensions.stream()
+ .filter(extension -> ConstantsPing.EXTENSION_URL_DOWNLOAD_SPEED.equals(extension.getUrl()))
+ .findFirst();
+ if (downloadSpeedExtension.isPresent())
+ {
+ extensions.remove(downloadSpeedExtension.get());
+ sortedExtensions.add(downloadSpeedExtension.get());
+ }
+
+ Optional uploadSpeedExtension = extensions.stream()
+ .filter(extension -> ConstantsPing.EXTENSION_URL_UPLOAD_SPEED.equals(extension.getUrl()))
+ .findFirst();
+ if (uploadSpeedExtension.isPresent())
+ {
+ extensions.remove(uploadSpeedExtension.get());
+ sortedExtensions.add(uploadSpeedExtension.get());
+ }
+
+ List errorMessageExtensions = extensions.stream()
+ .filter(extension -> ConstantsPing.EXTENSION_URL_ERROR_MESSAGE.equals(extension.getUrl())).toList();
+ if (!errorMessageExtensions.isEmpty())
+ {
+ extensions.removeAll(errorMessageExtensions);
+ sortedExtensions.addAll(errorMessageExtensions);
+ }
+
+ sortedExtensions.addAll(extensions);
+ pingStatusExtension.setExtension(sortedExtensions);
+ }
+ }
+}
diff --git a/src/main/resources/bpe/ping-autostart.bpmn b/src/main/resources/bpe/ping-autostart.bpmn
index c77a2c4d..c23a2b2f 100644
--- a/src/main/resources/bpe/ping-autostart.bpmn
+++ b/src/main/resources/bpe/ping-autostart.bpmn
@@ -100,7 +100,7 @@
-
+
no
diff --git a/src/main/resources/bpe/ping.bpmn b/src/main/resources/bpe/ping.bpmn
index 5d1ba29e..9f1f5703 100644
--- a/src/main/resources/bpe/ping.bpmn
+++ b/src/main/resources/bpe/ping.bpmn
@@ -1,265 +1,567 @@
-
-
-
-
-
- SequenceFlow_0k1j79c
- Flow_0j92st0
-
+
+
+
+
+
-
Flow_0j92st0
- Flow_099pk09
+ Flow_1bfs68o
R3/PT5S
- Flow_0v2ascf
+ Flow_10epxa2
-
-
-
-
-
+
Flow_0y9usku
Flow_1fjeq2h
-
- PT20S
+
+ PT200S
-
-
+
+
+ R3/PT5S
+
Flow_1lghrxh
- Flow_03hkxbe
-
+ Flow_1ewmc79
+
Flow_1j54c2s
- Flow_1lghrxh
Flow_0y9usku
+ Flow_1lghrxh
-
-
+
Flow_1fjeq2h
Flow_136htek
-
-
- Flow_03hkxbe
- Flow_0wmpprs
-
- Flow_1ipvu5v
+ Flow_08vgmf6
Flow_1j54c2s
Flow_101sqed
-
-
- Flow_101sqed
- Flow_16ssf4a
-
-
- ${execution.hasVariable('statusCode') && (statusCode == 'not-allowed' || statusCode == 'not-reachable')}
-
-
-
- Flow_0v2ascf
- Flow_1ipvu5v
-
-
-
- http://dsf.dev/bpe/Process/pong|#{version}
-
-
- http://dsf.dev/fhir/StructureDefinition/task-ping|#{version}
-
-
- ping
-
-
-
-
-
-
-
- Flow_0wmpprs
Flow_136htek
- Flow_16ssf4a
+ Flow_0upu487
Flow_1ho1hys
-
-
-
R3/PT5S
Flow_1ho1hys
+
+
+
+ http://dsf.dev/bpe/Process/pong|#{version}
+
+
+ ping
+
+
+ http://dsf.dev/fhir/StructureDefinition/task-ping|#{version}
+
+
+ Flow_10epxa2
+ Flow_08vgmf6
+
+
+ Flow_1jwekqw
+ Flow_13u1nzy
+ Flow_1yt9547
+
+
+ Flow_1yt9547
+ Flow_1v37fff
+
+
+
+
+ http://dsf.dev/fhir/StructureDefinition/task-cleanup-pong|#{version}
+
+
+ cleanupPong
+
+
+ http://dsf.dev/bpe/Process/pong|#{version}
+
+
+ Flow_1v37fff
+ Flow_0jcfur3
+ Flow_0klalf8
+
+
+ Flow_10h6pqh
+ Flow_0jcfur3
+
+
+ Flow_13u1nzy
+ Flow_0klalf8
+ Flow_03nx6rk
+
+
+
+ R3/PT5S
+
+ Flow_03nx6rk
+
+
+ Flow_10h6pqh
+
+
+
+
+
+
+
+
+
+
+ ${execution.hasVariable('statusCode') && (statusCode == 'not-allowed' || statusCode == 'not-reachable')}
+
+
+ ${downloadResourceSizeBytes < 0}
+
+
+
+
+
+
+
+
+ Flow_1ewmc79
+ Flow_1jwekqw
+
+
+
+
+
+ Flow_101sqed
+ Flow_0upu487
+
+
+ Information in message:
+- dowloadResourceSize: long
+- downloadResourceReference: Reference
+
+
+ Information in message:
+- downloadDurationMillis: long
+- downloadedBytes: long
+
+
+ downloads up to maxDownloadSizeBytes
+
+
+
+
+
+ Flow_152nb9r
+ Flow_1qz7z39
+
+
+ Flow_1bfs68o
+ Flow_0gubpgz
+
+
+ Flow_0gubpgz
+ Flow_1du5wys
+
Flow_1du5wys
+
+ Flow_0iuuyo1
+ Flow_1qz7z39
+ Flow_0ejw9k5
+ Flow_1c15ef2
+
+
+ Flow_1c15ef2
+ Flow_0j92st0
+
+
+ Flow_0fxlsv3
+ Flow_152nb9r
+ Flow_0iuuyo1
+
- SequenceFlow_0k1j79c
-
+ Flow_0e35w2m
+
-
+
+
+
+
-
-
- Flow_099pk09
- Flow_1du5wys
+
+ ${downloadResourceSizeBytes < 0}
+
+
+
+
+ Flow_0e35w2m
+ Flow_0fxlsv3
+
+
+ Flow_0ql2dtr
+
+
+
+
+
+ Flow_0ql2dtr
+ Flow_0ejw9k5
+
+
+ Includes download speeds and errors of all pongs
+
+
+ generates up to maxUploadSizeBystes
+
+
+ Process Parameters
+- downloadResourceSizeBytes read from Input Paramater (default tbd)
+- maxDownloadSizeBytes read from environment variable (default tbd)
+- maxUpdloadSizeBytes read from environment variables (default tbd)
+
+
+ Cleanup steps:
+- delete generated resource
+
+
+
+
+
+ Log = logger
+Save = save as execution variable
+Store = store on DSF FHIR server either as separate resource or output parameter
+
-
-
+
-
-
-
-
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
diff --git a/src/main/resources/bpe/pong.bpmn b/src/main/resources/bpe/pong.bpmn
index 39fdb0be..1fae2a96 100644
--- a/src/main/resources/bpe/pong.bpmn
+++ b/src/main/resources/bpe/pong.bpmn
@@ -1,97 +1,521 @@
-
-
+
+
- SequenceFlow_07w11cw
-
+ Flow_19b3cp4
+
-
-
-
- SequenceFlow_1ism9wt
-
-
-
- http://dsf.dev/fhir/StructureDefinition/task-pong|#{version}
-
-
- pong
-
-
- http://dsf.dev/bpe/Process/ping|#{version}
-
-
-
+
+ Flow_1gap0hi
+ Flow_10z0d4x
+ Flow_08gidyv
+
+
+ Flow_10z0d4x
+ Flow_0crmxc2
+
+
+ Flow_08gidyv
+ Flow_0gvrnxd
+ Flow_0dp8f59
+ Flow_1o3n9u6
+
+
+
+
+ http://dsf.dev/bpe/Process/ping|#{version}
+
+
+ pong
+
+
+ http://dsf.dev/fhir/StructureDefinition/task-pong|#{version}
+
+
+ Flow_1o3n9u6
+ Flow_0fzmjzb
+
+
+ Flow_0fzmjzb
+ Flow_0h8flp6
+ Flow_1bzjspe
+ Flow_00t1ck1
+
+
+ Flow_1bzjspe
+ Flow_0rj915n
+ Flow_17x98wg
+
+
+ Flow_0rj915n
+ Flow_1ttsk1o
+
+
+
+ Flow_17x98wg
+ Flow_1xfk4ds
+
+ ${execution.hasVariable("cleanupTimerDuration") ? cleanupTimerDuration : "PT20S"}
+
+
+
+ Flow_1jehvly
+ Flow_0yujsot
+ Flow_0x7t1ii
+
+
+ Flow_0uj7rm3
+ Flow_1jehvly
+
+
+ Flow_00t1ck1
+ Flow_1lfcycx
+ Flow_0h8flp6
+ Flow_0zib7wr
+
+
+ Flow_0x7t1ii
+ Flow_1w09zt7
+
+
+ Flow_1w09zt7
+ Flow_0gvrnxd
+
+
+ Flow_0uj7rm3
+
+
+
+
+ ${downloadResourceSizeBytes < 0}
+
+
+
+
+
+ ${execution.hasVariable('statusCode') && statusCode == 'not-reachable'}
+
+
+
+ ${downloadResourceSizeBytes < 0}
+
+
+
+
+
+
+
+
+ Flow_1j5lf0u
+ Flow_1oo1n55
+
+
+ Flow_1oo1n55
+ Flow_1fzloso
+
+
+
+ Flow_1bgedez
-
-
- SequenceFlow_07w11cw
- SequenceFlow_09i9zb8
+
+
+
+ Flow_1eh8lho
+ Flow_1n4fb8d
+ Flow_1lfcycx
+
+
+
+
+ Flow_1ttsk1o
+ Flow_1eh8lho
+
+
+
+
+
+ Flow_0crmxc2
+ Flow_0yujsot
+
+
+
+
+ Flow_1xfk4ds
+ Flow_1n4fb8d
-
- SequenceFlow_09i9zb8
- SequenceFlow_1ism9wt
+
+
+ Flow_0zib7wr
+ Flow_1bgedez
+
+
+ Flow_19b3cp4
+ Flow_1j5lf0u
+
+
+
+ Flow_0mgrru4
+
+
+
+ Flow_0mgrru4
+ Flow_0dp8f59
-
-
- Flow_0yr2pmf
+
+
+
+ Flow_1fzloso
+ Flow_1gap0hi
+
+
+ Flow_0qxt5zo
-
- Flow_0yr2pmf
-
+
+ Flow_0qxt5zo
+
-
+
+
+
+
+ Log = logger
+Save = save as execution variable
+Store = store on DSF FHIR server either as separate resource or output parameter
+
+
+ downloads up to maxDownloadSizeBytes
+
+
+ Information in message:
+- downloadedBytes: long
+- downloadedDurationMillis: long
+- downloadResourceReference: Reference
+- errors: List
+
+
+ Cleanup steps:
+- delete generated resource
+
+
+ Estimation based on download duration e.g. 10x or 20x download duration
+
+
+ generates up to maxUploadSizeBystes
+
+
+ Process Parameters
+- downloadResourceSizeBytes read from Input Paramater (no default, value from message expected)
+- maxDownloadSizeBytes read from environment variable (default tbd)
+- maxUpdloadSizeBytes read from environment variables (default tbd)
+
+
+
+
+
+
-
+
+
+
-
+
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
+
+
+
diff --git a/src/main/resources/fhir/ActivityDefinition/dsf-pong.xml b/src/main/resources/fhir/ActivityDefinition/dsf-pong.xml
index 1a877ce9..efde8372 100644
--- a/src/main/resources/fhir/ActivityDefinition/dsf-pong.xml
+++ b/src/main/resources/fhir/ActivityDefinition/dsf-pong.xml
@@ -31,6 +31,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fhir/CodeSystem/dsf-ping-status.xml b/src/main/resources/fhir/CodeSystem/dsf-ping-status.xml
index 1045752c..eed24337 100644
--- a/src/main/resources/fhir/CodeSystem/dsf-ping-status.xml
+++ b/src/main/resources/fhir/CodeSystem/dsf-ping-status.xml
@@ -5,7 +5,7 @@
-
+
@@ -42,8 +42,13 @@
-
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/fhir/CodeSystem/dsf-ping-units.xml b/src/main/resources/fhir/CodeSystem/dsf-ping-units.xml
new file mode 100644
index 00000000..b6109468
--- /dev/null
+++ b/src/main/resources/fhir/CodeSystem/dsf-ping-units.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/fhir/CodeSystem/dsf-ping.xml b/src/main/resources/fhir/CodeSystem/dsf-ping.xml
index a79fc556..aa93700c 100644
--- a/src/main/resources/fhir/CodeSystem/dsf-ping.xml
+++ b/src/main/resources/fhir/CodeSystem/dsf-ping.xml
@@ -5,7 +5,7 @@
-
+
@@ -46,4 +46,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/fhir/StructureDefinition/dsf-extension-network-speed.xml b/src/main/resources/fhir/StructureDefinition/dsf-extension-network-speed.xml
new file mode 100644
index 00000000..c82ca295
--- /dev/null
+++ b/src/main/resources/fhir/StructureDefinition/dsf-extension-network-speed.xml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/fhir/StructureDefinition/dsf-extension-ping-status.xml b/src/main/resources/fhir/StructureDefinition/dsf-extension-ping-status.xml
index 83251d5a..acf99fbe 100644
--- a/src/main/resources/fhir/StructureDefinition/dsf-extension-ping-status.xml
+++ b/src/main/resources/fhir/StructureDefinition/dsf-extension-ping-status.xml
@@ -5,7 +5,7 @@
-
+
@@ -109,7 +109,6 @@
-
@@ -122,9 +121,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/src/main/resources/fhir/StructureDefinition/dsf-task-cleanup-pong.xml b/src/main/resources/fhir/StructureDefinition/dsf-task-cleanup-pong.xml
new file mode 100644
index 00000000..a021340a
--- /dev/null
+++ b/src/main/resources/fhir/StructureDefinition/dsf-task-cleanup-pong.xml
@@ -0,0 +1,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/fhir/StructureDefinition/dsf-task-ping.xml b/src/main/resources/fhir/StructureDefinition/dsf-task-ping.xml
index 89346167..5acfec2e 100644
--- a/src/main/resources/fhir/StructureDefinition/dsf-task-ping.xml
+++ b/src/main/resources/fhir/StructureDefinition/dsf-task-ping.xml
@@ -31,7 +31,7 @@
-
+
@@ -70,7 +70,7 @@
-
+
@@ -81,7 +81,7 @@
-
+
@@ -117,6 +117,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -137,14 +229,14 @@
-
+
-
+
@@ -155,7 +247,7 @@
-
+
@@ -171,14 +263,14 @@
-
+
-
+
diff --git a/src/main/resources/fhir/StructureDefinition/dsf-task-pong.xml b/src/main/resources/fhir/StructureDefinition/dsf-task-pong.xml
index 225c13bb..50e1915e 100644
--- a/src/main/resources/fhir/StructureDefinition/dsf-task-pong.xml
+++ b/src/main/resources/fhir/StructureDefinition/dsf-task-pong.xml
@@ -31,7 +31,6 @@
-
@@ -60,5 +59,164 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/fhir/StructureDefinition/dsf-task-start-ping-autostart.xml b/src/main/resources/fhir/StructureDefinition/dsf-task-start-ping-autostart.xml
index 0683d5a6..969e6229 100644
--- a/src/main/resources/fhir/StructureDefinition/dsf-task-start-ping-autostart.xml
+++ b/src/main/resources/fhir/StructureDefinition/dsf-task-start-ping-autostart.xml
@@ -30,8 +30,8 @@
-
-
+
+
@@ -68,7 +68,7 @@
-
+
@@ -79,7 +79,7 @@
-
+
@@ -108,7 +108,7 @@
-
+
@@ -119,7 +119,7 @@
-
+
@@ -138,5 +138,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/fhir/StructureDefinition/dsf-task-start-ping.xml b/src/main/resources/fhir/StructureDefinition/dsf-task-start-ping.xml
index cf4363e7..ffe47756 100644
--- a/src/main/resources/fhir/StructureDefinition/dsf-task-start-ping.xml
+++ b/src/main/resources/fhir/StructureDefinition/dsf-task-start-ping.xml
@@ -31,7 +31,7 @@
-
+
@@ -68,7 +68,7 @@
-
+
@@ -79,7 +79,7 @@
-
+
@@ -92,6 +92,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -112,14 +176,14 @@
-
+
-
+
@@ -130,7 +194,7 @@
-
+
@@ -146,14 +210,14 @@
-
+
-
+
diff --git a/src/main/resources/fhir/Task/dsf-task-start-ping-autostart.xml b/src/main/resources/fhir/Task/dsf-task-start-ping-autostart.xml
index 60d7e8f5..0cff04de 100644
--- a/src/main/resources/fhir/Task/dsf-task-start-ping-autostart.xml
+++ b/src/main/resources/fhir/Task/dsf-task-start-ping-autostart.xml
@@ -38,19 +38,28 @@
-
-
+
+
-
+
-
-
+
+
-
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/fhir/Task/dsf-task-start-ping.xml b/src/main/resources/fhir/Task/dsf-task-start-ping.xml
index d8ef908b..29011e26 100644
--- a/src/main/resources/fhir/Task/dsf-task-start-ping.xml
+++ b/src/main/resources/fhir/Task/dsf-task-start-ping.xml
@@ -35,13 +35,22 @@
+
+
+
+
+
+
+
+
+
-
-
+
+
-
+
diff --git a/src/main/resources/fhir/ValueSet/dsf-ping-status.xml b/src/main/resources/fhir/ValueSet/dsf-ping-status.xml
index 0729a89a..9bed9fec 100644
--- a/src/main/resources/fhir/ValueSet/dsf-ping-status.xml
+++ b/src/main/resources/fhir/ValueSet/dsf-ping-status.xml
@@ -6,7 +6,7 @@
-
+
@@ -21,7 +21,7 @@
-
+
diff --git a/src/main/resources/fhir/ValueSet/dsf-ping-units.xml b/src/main/resources/fhir/ValueSet/dsf-ping-units.xml
new file mode 100644
index 00000000..fa619072
--- /dev/null
+++ b/src/main/resources/fhir/ValueSet/dsf-ping-units.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/resources/fhir/ValueSet/dsf-ping.xml b/src/main/resources/fhir/ValueSet/dsf-ping.xml
index 0fef6dbf..4984f57a 100644
--- a/src/main/resources/fhir/ValueSet/dsf-ping.xml
+++ b/src/main/resources/fhir/ValueSet/dsf-ping.xml
@@ -5,7 +5,7 @@
-
+
@@ -20,7 +20,7 @@
-
+
diff --git a/src/main/resources/fhir/ValueSet/dsf-pong-status.xml b/src/main/resources/fhir/ValueSet/dsf-pong-status.xml
index 09860584..97c471b7 100644
--- a/src/main/resources/fhir/ValueSet/dsf-pong-status.xml
+++ b/src/main/resources/fhir/ValueSet/dsf-pong-status.xml
@@ -5,7 +5,7 @@
-
+
@@ -20,7 +20,7 @@
-
+
@@ -31,8 +31,12 @@
-
-
+
+
+
+
+
+
diff --git a/src/test/java/dev/dsf/bpe/PingProcessPluginDefinitionTest.java b/src/test/java/dev/dsf/bpe/PingProcessPluginDefinitionTest.java
index 978fd13e..55e289ab 100644
--- a/src/test/java/dev/dsf/bpe/PingProcessPluginDefinitionTest.java
+++ b/src/test/java/dev/dsf/bpe/PingProcessPluginDefinitionTest.java
@@ -20,7 +20,7 @@ public void testResourceLoading() throws Exception
var ping = resourcesByProcessId.get(ConstantsPing.PROCESS_NAME_FULL_PING);
assertNotNull(ping);
- assertEquals(9, ping.stream().filter(this::exists).count());
+ assertEquals(13, ping.stream().filter(this::exists).count());
var pingAutostart = resourcesByProcessId.get(ConstantsPing.PROCESS_NAME_FULL_PING_AUTOSTART);
assertNotNull(pingAutostart);
@@ -28,7 +28,7 @@ public void testResourceLoading() throws Exception
var pong = resourcesByProcessId.get(ConstantsPing.PROCESS_NAME_FULL_PONG);
assertNotNull(pong);
- assertEquals(7, pong.stream().filter(this::exists).count());
+ assertEquals(10, pong.stream().filter(this::exists).count());
}
private boolean exists(String file)
diff --git a/src/test/java/dev/dsf/fhir/profiles/TaskProfileTest.java b/src/test/java/dev/dsf/fhir/profiles/TaskProfileTest.java
index 75c355aa..90c383a9 100644
--- a/src/test/java/dev/dsf/fhir/profiles/TaskProfileTest.java
+++ b/src/test/java/dev/dsf/fhir/profiles/TaskProfileTest.java
@@ -2,10 +2,19 @@
import static org.junit.Assert.assertEquals;
+import java.io.IOException;
+import java.io.InputStream;
+import java.math.BigDecimal;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
import java.util.UUID;
+import org.hl7.fhir.r4.model.IntegerType;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.ResourceType;
import org.hl7.fhir.r4.model.StringType;
@@ -17,11 +26,17 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhir.validation.ValidationResult;
import dev.dsf.bpe.ConstantsPing;
import dev.dsf.bpe.PingProcessPluginDefinition;
-import dev.dsf.bpe.util.PingStatusGenerator;
+import dev.dsf.bpe.util.task.input.generator.DownloadResourceReferenceGenerator;
+import dev.dsf.bpe.util.task.input.generator.DownloadResourceSizeGenerator;
+import dev.dsf.bpe.util.task.input.generator.ErrorMessageGenerator;
+import dev.dsf.bpe.util.task.input.generator.NetworkSpeedMetricGenerator;
+import dev.dsf.bpe.util.task.output.generator.PingStatusGenerator;
import dev.dsf.bpe.v1.constants.CodeSystems.BpmnMessage;
import dev.dsf.bpe.v1.constants.NamingSystems.EndpointIdentifier;
import dev.dsf.bpe.v1.constants.NamingSystems.OrganizationIdentifier;
@@ -39,13 +54,15 @@ public class TaskProfileTest
@ClassRule
public static final ValidationSupportRule validationRule = new ValidationSupportRule(def.getResourceVersion(),
def.getResourceReleaseDate(),
- Arrays.asList("dsf-task-base-1.0.0.xml", "dsf-extension-ping-status.xml", "dsf-task-ping.xml",
- "dsf-task-pong.xml", "dsf-task-start-ping.xml", "dsf-task-start-ping-autostart.xml",
- "dsf-task-stop-ping-autostart.xml"),
- Arrays.asList("dsf-read-access-tag-1.0.0.xml", "dsf-bpmn-message-1.0.0.xml", "dsf-ping.xml",
- "dsf-ping-status.xml"),
- Arrays.asList("dsf-read-access-tag-1.0.0.xml", "dsf-bpmn-message-1.0.0.xml", "dsf-ping.xml",
- "dsf-ping-status.xml", "dsf-pong-status.xml"));
+ Arrays.asList("dsf-task-base-1.0.0.xml", "dsf-extension-network-speed.xml", "dsf-extension-ping-status.xml",
+ "dsf-extension-ping-status-1_0.xml", "dsf-task-ping.xml", "dsf-task-pong.xml",
+ "dsf-task-start-ping.xml", "dsf-task-start-ping-autostart.xml", "dsf-task-stop-ping-autostart.xml",
+ "dsf-task-cleanup-pong.xml"),
+ Arrays.asList("dsf-read-access-tag-1.0.0.xml", "dsf-bpmn-message-1.0.0.xml", "dsf-ping-1_0.xml",
+ "dsf-ping.xml", "dsf-ping-status-1_0.xml", "dsf-ping-status.xml", "dsf-ping-units.xml"),
+ Arrays.asList("dsf-read-access-tag-1.0.0.xml", "dsf-bpmn-message-1.0.0.xml", "dsf-ping-1_0.xml",
+ "dsf-ping.xml", "dsf-ping-status-1_0.xml", "dsf-ping-status.xml", "dsf-pong-status-1_0.xml",
+ "dsf-pong-status.xml", "dsf-ping-units.xml"));
private ResourceValidator resourceValidator = new ResourceValidatorImpl(validationRule.getFhirContext(),
validationRule.getValidationSupport());
@@ -126,6 +143,8 @@ private Task createValidTaskStartAutostartProcess()
task.addInput().setValue(new StringType(ConstantsPing.PROFILE_DSF_TASK_START_PING_AUTOSTART_MESSAGE_NAME))
.getType().addCoding(BpmnMessage.messageName());
+ task.addInput(DownloadResourceSizeGenerator.create(0));
+
return task;
}
@@ -173,6 +192,21 @@ public void testTaskStartPingProcessProfileValid() throws Exception
|| ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
}
+ @Test
+ public void testTaskStartPingProcessProfileValidWithErrorMessages() throws Exception
+ {
+ Task task = createValidTaskStartPingProcess();
+
+ dev.dsf.bpe.util.task.output.generator.ErrorMessageGenerator.create(List.of("Foo", "Bar"))
+ .forEach(task::addOutput);
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
@Test
public void testTaskStartPingProcessProfileValidWithTargetEndpoints() throws Exception
{
@@ -235,10 +269,55 @@ public String getCorrelationKey()
};
Task task = createValidTaskStartPingProcess();
- task.addOutput().setValue(new StringType(UUID.randomUUID().toString())).getType()
+ task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType()
.addCoding(BpmnMessage.businessKey());
- task.addOutput(new PingStatusGenerator().createPingStatusOutput(target,
- ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_REACHABLE, "some error message"));
+ task.addOutput(PingStatusGenerator.createPingStatusOutput(target,
+ ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_NOT_REACHABLE, List.of("some error message")));
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testTaskStartPingProcessProfileValidWithBusinessKeyAndPingStatusOutputWithDownloadAndUploadSpeeds()
+ throws Exception
+ {
+ Target target = new Target()
+ {
+ @Override
+ public String getOrganizationIdentifierValue()
+ {
+ return "target.org";
+ }
+
+ @Override
+ public String getEndpointUrl()
+ {
+ return "https://endpoint.target.org/fhir";
+ }
+
+ @Override
+ public String getEndpointIdentifierValue()
+ {
+ return "endpoint.target.org";
+ }
+
+ @Override
+ public String getCorrelationKey()
+ {
+ return UUID.randomUUID().toString();
+ }
+ };
+
+ Task task = createValidTaskStartPingProcess();
+ task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType()
+ .addCoding(BpmnMessage.businessKey());
+ task.addOutput(PingStatusGenerator.createPingStatusOutput(target,
+ ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_RECEIVED, BigDecimal.ZERO, BigDecimal.ZERO,
+ ConstantsPing.CODESYSTEM_DSF_PING_UNITS_VALUE_BITS_PER_SECOND));
ValidationResult result = resourceValidator.validate(task);
ValidationSupportRule.logValidationMessages(logger, result);
@@ -301,6 +380,8 @@ private Task createValidTaskStartPingProcess()
task.addInput().setValue(new StringType(ConstantsPing.PROFILE_DSF_TASK_START_PING_MESSAGE_NAME)).getType()
.addCoding(BpmnMessage.messageName());
+ task.addInput().setValue(new IntegerType(1)).getType().addCoding().setSystem(ConstantsPing.CODESYSTEM_DSF_PING)
+ .setCode(ConstantsPing.CODESYSTEM_DSF_PING_VALUE_DOWNLOAD_RESOURCE_SIZE_BYTES);
return task;
}
@@ -348,7 +429,51 @@ public String getCorrelationKey()
};
Task task = createValidTaskPing();
task.addOutput(new PingStatusGenerator().createPongStatusOutput(target,
- ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_SEND));
+ ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_SENT));
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testTaskPingValidWithPingStatusOutputAndDownloadResourceSizeAndDownloadResourceReference()
+ throws Exception
+ {
+ Target target = new Target()
+ {
+ @Override
+ public String getOrganizationIdentifierValue()
+ {
+ return "target.org";
+ }
+
+ @Override
+ public String getEndpointUrl()
+ {
+ return "https://endpoint.target.org/fhir";
+ }
+
+ @Override
+ public String getEndpointIdentifierValue()
+ {
+ return "endpoint.target.org";
+ }
+
+ @Override
+ public String getCorrelationKey()
+ {
+ return UUID.randomUUID().toString();
+ }
+ };
+ Task task = createValidTaskPing();
+ task.addOutput(new PingStatusGenerator().createPongStatusOutput(target,
+ ConstantsPing.CODESYSTEM_DSF_PING_STATUS_VALUE_PONG_SENT));
+
+ task.addInput(DownloadResourceSizeGenerator.create(1000));
+ task.addInput(DownloadResourceReferenceGenerator.create("https://test.endpoint.org/fhir/Binary"));
ValidationResult result = resourceValidator.validate(task);
ValidationSupportRule.logValidationMessages(logger, result);
@@ -397,6 +522,52 @@ public void testTaskPongValid() throws Exception
|| ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
}
+ @Test
+ public void testTaskPongValidWithReferenceAndDownloadedDurationMillisAndDownloadedBytesPresent()
+ {
+ Task task = createValidTaskPong();
+
+ task.addInput(DownloadResourceReferenceGenerator.create("https://test.endpoint.org/fhir/Binary"));
+ task.addInput(NetworkSpeedMetricGenerator.createDownloadedBytes(1000));
+ task.addInput(NetworkSpeedMetricGenerator.createDownloadedDurationMillis(1000));
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testTaskPongValidWithMultipleErrorMessages()
+ {
+ Task task = createValidTaskPong();
+
+ task.addInput(DownloadResourceReferenceGenerator.create("https://test.endpoint.org/fhir/Binary"));
+ task.addInput(NetworkSpeedMetricGenerator.createDownloadedBytes(1000));
+ task.addInput(NetworkSpeedMetricGenerator.createDownloadedDurationMillis(1000));
+ task.addInput(ErrorMessageGenerator.create("Something went wrong"));
+ task.addInput(ErrorMessageGenerator.create("Something went wrong really badly"));
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testTaskCleanupPongValid()
+ {
+ Task task = createValidTaskCleanupPong();
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
private Task createValidTaskPong()
{
Task task = new Task();
@@ -419,4 +590,97 @@ private Task createValidTaskPong()
return task;
}
+
+ private Task createValidTaskCleanupPong()
+ {
+ Task task = new Task();
+ task.getMeta().addProfile(ConstantsPing.PROFILE_DSF_TASK_CLEANUP_PONG);
+ task.setInstantiatesCanonical(
+ ConstantsPing.PROFILE_DSF_TASK_CLEANUP_PONG_PROCESS_URI + "|" + def.getResourceVersion());
+ task.setStatus(TaskStatus.REQUESTED);
+ task.setIntent(TaskIntent.ORDER);
+ task.setAuthoredOn(new Date());
+ task.getRequester().setType(ResourceType.Organization.name())
+ .setIdentifier(OrganizationIdentifier.withValue("DIC 1"));
+ task.getRestriction().addRecipient().setType(ResourceType.Organization.name())
+ .setIdentifier(OrganizationIdentifier.withValue("TTP"));
+
+ task.addInput().setValue(new StringType(ConstantsPing.PROFILE_DSF_TASK_CLEANUP_PONG_MESSAGE_NAME)).getType()
+ .addCoding(BpmnMessage.messageName());
+ task.addInput().setValue(new StringType(UUID.randomUUID().toString())).getType()
+ .addCoding(BpmnMessage.businessKey());
+
+ task.addInput(NetworkSpeedMetricGenerator.createDownloadedBytes(1000));
+ task.addInput(NetworkSpeedMetricGenerator.createDownloadedDurationMillis(1000));
+ return task;
+ }
+
+ @Test
+ public void testDraftTaskStartPingValid() throws IOException
+ {
+ FhirContext ctx = FhirContext.forR4();
+ InputStream fileInputStream = getClass().getClassLoader()
+ .getResourceAsStream("fhir/Task/dsf-task-start-ping.xml");
+ String xml = new String(fileInputStream.readAllBytes());
+ xml = fillPlaceholders(xml);
+ fileInputStream.close();
+
+ IParser parser = ctx.newXmlParser();
+ Task task = parser.parseResource(Task.class, xml);
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testDraftTaskStartPingAutostartValid() throws IOException
+ {
+ FhirContext ctx = FhirContext.forR4();
+ InputStream fileInputStream = getClass().getClassLoader()
+ .getResourceAsStream("fhir/Task/dsf-task-start-ping-autostart.xml");
+ String xml = new String(fileInputStream.readAllBytes());
+ xml = fillPlaceholders(xml);
+ fileInputStream.close();
+
+ IParser parser = ctx.newXmlParser();
+ Task task = parser.parseResource(Task.class, xml);
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ @Test
+ public void testDraftTaskStopPingAutostartValid() throws IOException
+ {
+ FhirContext ctx = FhirContext.forR4();
+ InputStream fileInputStream = getClass().getClassLoader()
+ .getResourceAsStream("fhir/Task/dsf-task-stop-ping-autostart.xml");
+ String xml = new String(fileInputStream.readAllBytes());
+ xml = fillPlaceholders(xml);
+ fileInputStream.close();
+
+ IParser parser = ctx.newXmlParser();
+ Task task = parser.parseResource(Task.class, xml);
+
+ ValidationResult result = resourceValidator.validate(task);
+ ValidationSupportRule.logValidationMessages(logger, result);
+
+ assertEquals(0, result.getMessages().stream().filter(m -> ResultSeverityEnum.ERROR.equals(m.getSeverity())
+ || ResultSeverityEnum.FATAL.equals(m.getSeverity())).count());
+ }
+
+ private String fillPlaceholders(String xml)
+ {
+ DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ xml = xml.replaceAll("#\\{version}", def.getResourceVersion());
+ xml = xml.replaceAll("#\\{date}",
+ dtf.format(LocalDate.ofInstant(Instant.now(), TimeZone.getDefault().toZoneId())));
+ return xml;
+ }
}
diff --git a/src/test/java/dev/dsf/library/InputStreamTest.java b/src/test/java/dev/dsf/library/InputStreamTest.java
new file mode 100644
index 00000000..8ca977ac
--- /dev/null
+++ b/src/test/java/dev/dsf/library/InputStreamTest.java
@@ -0,0 +1,51 @@
+package dev.dsf.library;
+
+import static org.junit.Assert.assertThrows;
+
+import java.io.ByteArrayInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Random;
+
+import org.junit.Test;
+
+public class InputStreamTest
+{
+ @Test
+ public void testSkipNBytesSuccessWhenAllSkipped() throws IOException
+ {
+ int length = 1000;
+ int toSkip = length;
+ byte[] data = randomData(length);
+ InputStream in = new ByteArrayInputStream(data);
+ in.skipNBytes(toSkip);
+ }
+
+ @Test
+ public void testSkipNBytesSuccessWhenSomeSkipped() throws IOException
+ {
+ int length = 1000;
+ int toSkip = length / 2;
+ byte[] data = randomData(length);
+ InputStream in = new ByteArrayInputStream(data);
+ in.skipNBytes(toSkip);
+ }
+
+ @Test
+ public void testSkipNBytesFailOnSkipTooMany() throws IOException
+ {
+ int length = 1000;
+ int toSkip = length + 1;
+ byte[] data = randomData(length);
+ InputStream in = new ByteArrayInputStream(data);
+ assertThrows(EOFException.class, () -> in.skipNBytes(toSkip));
+ }
+
+ private byte[] randomData(int length)
+ {
+ byte[] data = new byte[length];
+ new Random().nextBytes(data);
+ return data;
+ }
+}
diff --git a/src/test/resources/fhir/CodeSystem/dsf-ping-1_0.xml b/src/test/resources/fhir/CodeSystem/dsf-ping-1_0.xml
new file mode 100644
index 00000000..630c9073
--- /dev/null
+++ b/src/test/resources/fhir/CodeSystem/dsf-ping-1_0.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/fhir/CodeSystem/dsf-ping-status-1_0.xml b/src/test/resources/fhir/CodeSystem/dsf-ping-status-1_0.xml
new file mode 100644
index 00000000..62ebe1cb
--- /dev/null
+++ b/src/test/resources/fhir/CodeSystem/dsf-ping-status-1_0.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/fhir/StructureDefinition/dsf-extension-ping-status-1_0.xml b/src/test/resources/fhir/StructureDefinition/dsf-extension-ping-status-1_0.xml
new file mode 100644
index 00000000..3917b793
--- /dev/null
+++ b/src/test/resources/fhir/StructureDefinition/dsf-extension-ping-status-1_0.xml
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/fhir/ValueSet/dsf-ping-1_0.xml b/src/test/resources/fhir/ValueSet/dsf-ping-1_0.xml
new file mode 100644
index 00000000..4784f28a
--- /dev/null
+++ b/src/test/resources/fhir/ValueSet/dsf-ping-1_0.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/fhir/ValueSet/dsf-ping-status-1_0.xml b/src/test/resources/fhir/ValueSet/dsf-ping-status-1_0.xml
new file mode 100644
index 00000000..cae323ec
--- /dev/null
+++ b/src/test/resources/fhir/ValueSet/dsf-ping-status-1_0.xml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/test/resources/fhir/ValueSet/dsf-pong-status-1_0.xml b/src/test/resources/fhir/ValueSet/dsf-pong-status-1_0.xml
new file mode 100644
index 00000000..38a2020a
--- /dev/null
+++ b/src/test/resources/fhir/ValueSet/dsf-pong-status-1_0.xml
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file