Skip to content

Commit cd0c5f7

Browse files
committed
add check for resource type and request method for bundle entries
1 parent 33b0fc0 commit cd0c5f7

File tree

6 files changed

+217
-40
lines changed

6 files changed

+217
-40
lines changed

src/main/java/dev/dsf/bpe/ConstantsAllowList.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,7 @@ public interface ConstantsAllowList
2020
String PROFILE_DSF_TASK_UPDATE_ALLOW_LIST = "http://dsf.dev/fhir/StructureDefinition/task-update-allow-list";
2121
String PROFILE_DSF_TASK_UPDATE_ALLOW_LIST_PROCESS_URI = PROCESS_DSF_URI_BASE + PROCESS_NAME_UPDATE_ALLOW_LIST;
2222
String PROFILE_DSF_TASK_UPDATE_ALLOW_LIST_MESSAGE_NAME = "updateAllowListMessage";
23+
24+
String BPMN_EXECUTION_VARIABLE_BUNDLE = "bundle";
25+
String BPMN_EXECUTION_VARIABLE_BUNDLE_URL = "bundleUrl";
2326
}
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package dev.dsf.bpe.service;
2+
3+
import java.util.EnumSet;
4+
import java.util.function.Predicate;
5+
6+
import org.camunda.bpm.engine.delegate.DelegateExecution;
7+
import org.hl7.fhir.r4.model.Bundle;
8+
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
9+
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
10+
import org.hl7.fhir.r4.model.Endpoint;
11+
import org.hl7.fhir.r4.model.Organization;
12+
import org.hl7.fhir.r4.model.OrganizationAffiliation;
13+
import org.hl7.fhir.r4.model.Resource;
14+
import org.hl7.fhir.r4.model.StringType;
15+
import org.hl7.fhir.r4.model.Task;
16+
import org.slf4j.Logger;
17+
import org.slf4j.LoggerFactory;
18+
19+
import dev.dsf.bpe.ConstantsAllowList;
20+
import dev.dsf.bpe.v1.ProcessPluginApi;
21+
import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
22+
import dev.dsf.bpe.v1.constants.CodeSystems;
23+
import dev.dsf.bpe.v1.variables.Variables;
24+
25+
public class CheckAllowList extends AbstractServiceDelegate
26+
{
27+
private static final Logger logger = LoggerFactory.getLogger(CheckAllowList.class);
28+
29+
public CheckAllowList(ProcessPluginApi api)
30+
{
31+
super(api);
32+
}
33+
34+
@Override
35+
protected void doExecute(DelegateExecution execution, Variables variables)
36+
{
37+
Bundle bundle = variables.getResource(ConstantsAllowList.BPMN_EXECUTION_VARIABLE_BUNDLE);
38+
String bundleUrl = variables.getString(ConstantsAllowList.BPMN_EXECUTION_VARIABLE_BUNDLE_URL);
39+
40+
if (!EnumSet.of(Bundle.BundleType.TRANSACTION, Bundle.BundleType.BATCH).contains(bundle.getType()))
41+
{
42+
logger.error("Bundle type TRANSACTION or BATCH expected, but got '{}' in Bundle with id '{}'",
43+
bundle.getType(), bundleUrl);
44+
throw new RuntimeException("Bundle type TRANSACTION or BATCH expected, but got '" + bundle.getType()
45+
+ "' in Bundle with id '" + bundleUrl + "'");
46+
}
47+
48+
Task task = variables.getStartTask();
49+
50+
if (bundle.getEntry().stream().anyMatch(entryNotAllowedWithError(task, bundleUrl)))
51+
{
52+
variables.updateTask(task);
53+
54+
logger.error("Expected Bundle with id '{}' containing only resource types Organization, "
55+
+ "OrganizationAffiliation or Endpoint and request methods PUT or DELETE, but found different "
56+
+ "types or methods.", bundleUrl);
57+
throw new RuntimeException("Expected Bundle with id '" + bundleUrl + "'containing only resource "
58+
+ "types Organization, OrganizationAffiliation or Endpoint and "
59+
+ "request methods PUT or DELETE, but found different types or methods.");
60+
}
61+
}
62+
63+
private Predicate<BundleEntryComponent> entryNotAllowedWithError(Task task, String bundleUrl)
64+
{
65+
return entry ->
66+
{
67+
boolean resourceNotAllowed = resourceNotAllowedWithError(entry, task, bundleUrl);
68+
boolean requestNotAllowed = requestNotAllowedWithError(entry, task, bundleUrl);
69+
70+
// Split into two method calls and not inline to ensure that both methods
71+
// are executed so that all given error messages can be written to Task.output
72+
return resourceNotAllowed || requestNotAllowed;
73+
};
74+
}
75+
76+
private boolean resourceNotAllowedWithError(BundleEntryComponent entry, Task task, String bundleUrl)
77+
{
78+
Resource resource = entry.getResource();
79+
boolean resourceAllowed = (resource instanceof Organization || resource instanceof OrganizationAffiliation
80+
|| resource instanceof Endpoint);
81+
82+
if (!resourceAllowed)
83+
addError(task, "Resource of type '" + resource.getResourceType().name()
84+
+ "' not allowed in Bundle with id '" + bundleUrl + "'");
85+
86+
return !resourceAllowed;
87+
}
88+
89+
private boolean requestNotAllowedWithError(BundleEntryComponent entry, Task task, String bundleUrl)
90+
{
91+
boolean requestAllowed = false;
92+
93+
if (entry.hasRequest())
94+
requestAllowed = EnumSet.of(HTTPVerb.PUT, HTTPVerb.DELETE).contains(entry.getRequest().getMethod());
95+
96+
if (!requestAllowed)
97+
addError(task, "Request with Method '" + entry.getRequest().getMethod()
98+
+ "' not allowed in Bundle with id '" + bundleUrl + "'");
99+
100+
return !requestAllowed;
101+
}
102+
103+
private void addError(Task task, String message)
104+
{
105+
logger.warn(message);
106+
task.addOutput(api.getTaskHelper().createOutput(new StringType(message), CodeSystems.BpmnMessage.error()));
107+
}
108+
}

src/main/java/dev/dsf/bpe/service/DownloadAllowList.java

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
package dev.dsf.bpe.service;
22

3-
import java.util.EnumSet;
43
import java.util.List;
54

65
import org.camunda.bpm.engine.delegate.DelegateExecution;
76
import org.hl7.fhir.r4.model.Bundle;
8-
import org.hl7.fhir.r4.model.Bundle.BundleType;
97
import org.hl7.fhir.r4.model.IdType;
108
import org.hl7.fhir.r4.model.Reference;
119
import org.hl7.fhir.r4.model.Task;
@@ -29,47 +27,31 @@ public DownloadAllowList(ProcessPluginApi api)
2927
}
3028

3129
@Override
32-
protected void doExecute(DelegateExecution execution, Variables variables) throws Exception
30+
protected void doExecute(DelegateExecution execution, Variables variables)
3331
{
3432
Task task = variables.getStartTask();
3533
IdType bundleId = getBundleId(task);
3634
FhirWebserviceClient requesterClient = api.getFhirWebserviceClientProvider()
3735
.getWebserviceClient(bundleId.getBaseUrl());
3836

39-
Bundle bundle;
4037
try
4138
{
39+
Bundle bundle;
40+
4241
if (bundleId.hasVersionIdPart())
4342
bundle = requesterClient.read(Bundle.class, bundleId.getIdPart(), bundleId.getVersionIdPart());
4443
else
4544
bundle = requesterClient.read(Bundle.class, bundleId.getIdPart());
45+
46+
variables.setString(ConstantsAllowList.BPMN_EXECUTION_VARIABLE_BUNDLE_URL, bundleId.getValue());
47+
variables.setResource(ConstantsAllowList.BPMN_EXECUTION_VARIABLE_BUNDLE, bundle);
4648
}
4749
catch (WebApplicationException e)
4850
{
49-
logger.error("Error while reading Bundle with id {} from organization {}: {}", bundleId.getValue(),
51+
logger.error("Error while reading Bundle with id '{}' from organization {}: {}", bundleId.getValue(),
5052
task.getRequester().getReference(), e.getMessage());
51-
throw new RuntimeException("Error while reading Bundle with id " + bundleId.getValue()
52-
+ " from organization " + task.getRequester().getReference() + ", " + e.getMessage(), e);
53-
}
54-
55-
if (!EnumSet.of(BundleType.TRANSACTION, BundleType.BATCH).contains(bundle.getType()))
56-
{
57-
logger.error("Bundle type TRANSACTION or BATCH expected, but got {}", bundle.getType());
58-
throw new RuntimeException("Bundle type TRANSACTION or BATCH expected, but got " + bundle.getType());
59-
}
60-
61-
try
62-
{
63-
logger.debug("Posting bundle to local endpoint: {}",
64-
api.getFhirContext().newXmlParser().encodeResourceToString(bundle));
65-
api.getFhirWebserviceClientProvider().getLocalWebserviceClient().withMinimalReturn().postBundle(bundle);
66-
}
67-
catch (Exception e)
68-
{
69-
logger.error("Error while executing Bundle with id {} from organization {} locally: {}",
70-
bundleId.getValue(), task.getRequester().getReference(), e.getMessage());
71-
throw new RuntimeException("Error while executing Bundle with id " + bundleId.getValue()
72-
+ " from organization " + task.getRequester().getReference() + " locally, " + e.getMessage(), e);
53+
throw new RuntimeException("Error while reading Bundle with id '" + bundleId.getValue()
54+
+ "' from organization " + task.getRequester().getReference() + ": " + e.getMessage(), e);
7355
}
7456
}
7557

@@ -82,19 +64,19 @@ private IdType getBundleId(Task task)
8264

8365
if (bundleReferences.size() != 1)
8466
{
85-
logger.error("Task input parameter {} contains unexpected number of Bundle IDs, expected 1, got {}",
67+
logger.error("Task input parameter '{}' contains unexpected number of Bundle IDs, expected 1, got {}",
8668
ConstantsAllowList.CODESYSTEM_DSF_ALLOW_LIST_VALUE_ALLOW_LIST, bundleReferences.size());
8769
throw new RuntimeException(
88-
"Task input parameter " + ConstantsAllowList.CODESYSTEM_DSF_ALLOW_LIST_VALUE_ALLOW_LIST
89-
+ " contains unexpected number of Bundle IDs, expected 1, got " + bundleReferences.size());
70+
"Task input parameter '" + ConstantsAllowList.CODESYSTEM_DSF_ALLOW_LIST_VALUE_ALLOW_LIST
71+
+ "' contains unexpected number of Bundle IDs, expected 1, got " + bundleReferences.size());
9072
}
9173
else if (!bundleReferences.get(0).hasReference()
9274
|| !bundleReferences.get(0).getReference().contains("/Bundle/"))
9375
{
94-
logger.error("Task input parameter {} has no Bundle reference",
76+
logger.error("Task input parameter '{}' has no Bundle reference",
9577
ConstantsAllowList.CODESYSTEM_DSF_ALLOW_LIST_VALUE_ALLOW_LIST);
96-
throw new RuntimeException("Task input parameter "
97-
+ ConstantsAllowList.CODESYSTEM_DSF_ALLOW_LIST_VALUE_ALLOW_LIST + " has no Bundle reference");
78+
throw new RuntimeException("Task input parameter '"
79+
+ ConstantsAllowList.CODESYSTEM_DSF_ALLOW_LIST_VALUE_ALLOW_LIST + "' has no Bundle reference");
9880
}
9981

10082
return new IdType(bundleReferences.get(0).getReference());
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package dev.dsf.bpe.service;
2+
3+
import org.camunda.bpm.engine.delegate.DelegateExecution;
4+
import org.hl7.fhir.r4.model.Bundle;
5+
import org.hl7.fhir.r4.model.Task;
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
9+
import dev.dsf.bpe.ConstantsAllowList;
10+
import dev.dsf.bpe.v1.ProcessPluginApi;
11+
import dev.dsf.bpe.v1.activity.AbstractServiceDelegate;
12+
import dev.dsf.bpe.v1.variables.Variables;
13+
14+
public class InsertAllowList extends AbstractServiceDelegate
15+
{
16+
private static final Logger logger = LoggerFactory.getLogger(InsertAllowList.class);
17+
18+
public InsertAllowList(ProcessPluginApi api)
19+
{
20+
super(api);
21+
}
22+
23+
@Override
24+
protected void doExecute(DelegateExecution execution, Variables variables)
25+
{
26+
Task task = variables.getStartTask();
27+
Bundle bundle = variables.getResource(ConstantsAllowList.BPMN_EXECUTION_VARIABLE_BUNDLE);
28+
String bundleUrl = variables.getString(ConstantsAllowList.BPMN_EXECUTION_VARIABLE_BUNDLE_URL);
29+
30+
try
31+
{
32+
logger.debug("Posting bundle to local endpoint: {}",
33+
api.getFhirContext().newXmlParser().encodeResourceToString(bundle));
34+
api.getFhirWebserviceClientProvider().getLocalWebserviceClient().withMinimalReturn().postBundle(bundle);
35+
}
36+
catch (Exception e)
37+
{
38+
logger.error("Error while executing Bundle with id '{}' from organization {} locally: {}", bundleUrl,
39+
task.getRequester().getReference(), e.getMessage());
40+
throw new RuntimeException("Error while executing Bundle with id '" + bundleUrl + "' from organization "
41+
+ task.getRequester().getReference() + " locally, " + e.getMessage(), e);
42+
}
43+
}
44+
}

src/main/java/dev/dsf/bpe/spring/config/AllowListConfig.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
import org.springframework.context.annotation.Configuration;
77
import org.springframework.context.annotation.Scope;
88

9+
import dev.dsf.bpe.service.CheckAllowList;
910
import dev.dsf.bpe.service.DownloadAllowList;
11+
import dev.dsf.bpe.service.InsertAllowList;
1012
import dev.dsf.bpe.service.UpdateAllowList;
1113
import dev.dsf.bpe.v1.ProcessPluginApi;
1214

@@ -29,4 +31,18 @@ public DownloadAllowList downloadAllowList()
2931
{
3032
return new DownloadAllowList(api);
3133
}
34+
35+
@Bean
36+
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
37+
public CheckAllowList checkAllowList()
38+
{
39+
return new CheckAllowList(api);
40+
}
41+
42+
@Bean
43+
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
44+
public InsertAllowList insertAllowList()
45+
{
46+
return new InsertAllowList(api);
47+
}
3248
}
Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1yb5vw3" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="4.8.1">
2+
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" id="Definitions_1yb5vw3" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="5.0.0">
33
<bpmn:process id="dsfdev_downloadAllowList" isExecutable="true" camunda:versionTag="#{version}">
44
<bpmn:sequenceFlow id="SequenceFlow_0bbhq2r" sourceRef="StartEvent_1" targetRef="downloadAllowListTask" />
55
<bpmn:endEvent id="EndEvent_0xd0x8k">
6-
<bpmn:incoming>SequenceFlow_0oyvmcd</bpmn:incoming>
6+
<bpmn:incoming>Flow_0g4jed4</bpmn:incoming>
77
</bpmn:endEvent>
8-
<bpmn:sequenceFlow id="SequenceFlow_0oyvmcd" sourceRef="downloadAllowListTask" targetRef="EndEvent_0xd0x8k" />
8+
<bpmn:sequenceFlow id="SequenceFlow_0oyvmcd" sourceRef="downloadAllowListTask" targetRef="checkAllowListTask" />
99
<bpmn:serviceTask id="downloadAllowListTask" name="downloadAllowList" camunda:class="dev.dsf.bpe.service.DownloadAllowList">
1010
<bpmn:incoming>SequenceFlow_0bbhq2r</bpmn:incoming>
1111
<bpmn:outgoing>SequenceFlow_0oyvmcd</bpmn:outgoing>
@@ -14,27 +14,51 @@
1414
<bpmn:outgoing>SequenceFlow_0bbhq2r</bpmn:outgoing>
1515
<bpmn:messageEventDefinition messageRef="Message_1nn2wdw" />
1616
</bpmn:startEvent>
17+
<bpmn:sequenceFlow id="Flow_0kev1xq" sourceRef="checkAllowListTask" targetRef="insertAllowListTask" />
18+
<bpmn:sequenceFlow id="Flow_0g4jed4" sourceRef="insertAllowListTask" targetRef="EndEvent_0xd0x8k" />
19+
<bpmn:serviceTask id="checkAllowListTask" name="checkAllowList" camunda:class="dev.dsf.bpe.service.CheckAllowList">
20+
<bpmn:incoming>SequenceFlow_0oyvmcd</bpmn:incoming>
21+
<bpmn:outgoing>Flow_0kev1xq</bpmn:outgoing>
22+
</bpmn:serviceTask>
23+
<bpmn:serviceTask id="insertAllowListTask" name="insertAllowList" camunda:class="dev.dsf.bpe.service.InsertAllowList">
24+
<bpmn:incoming>Flow_0kev1xq</bpmn:incoming>
25+
<bpmn:outgoing>Flow_0g4jed4</bpmn:outgoing>
26+
</bpmn:serviceTask>
1727
</bpmn:process>
1828
<bpmn:message id="Message_1nn2wdw" name="downloadAllowListMessage" />
1929
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
2030
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="dsfdev_downloadAllowList">
2131
<bpmndi:BPMNEdge id="SequenceFlow_0oyvmcd_di" bpmnElement="SequenceFlow_0oyvmcd">
2232
<di:waypoint x="365" y="121" />
23-
<di:waypoint x="415" y="121" />
33+
<di:waypoint x="430" y="121" />
2434
</bpmndi:BPMNEdge>
2535
<bpmndi:BPMNEdge id="SequenceFlow_0bbhq2r_di" bpmnElement="SequenceFlow_0bbhq2r">
2636
<di:waypoint x="215" y="121" />
2737
<di:waypoint x="265" y="121" />
2838
</bpmndi:BPMNEdge>
29-
<bpmndi:BPMNShape id="EndEvent_0xd0x8k_di" bpmnElement="EndEvent_0xd0x8k">
30-
<dc:Bounds x="415" y="103" width="36" height="36" />
31-
</bpmndi:BPMNShape>
39+
<bpmndi:BPMNEdge id="Flow_0kev1xq_di" bpmnElement="Flow_0kev1xq">
40+
<di:waypoint x="530" y="121" />
41+
<di:waypoint x="590" y="121" />
42+
</bpmndi:BPMNEdge>
43+
<bpmndi:BPMNEdge id="Flow_0g4jed4_di" bpmnElement="Flow_0g4jed4">
44+
<di:waypoint x="690" y="121" />
45+
<di:waypoint x="742" y="121" />
46+
</bpmndi:BPMNEdge>
3247
<bpmndi:BPMNShape id="ServiceTask_0um3ad2_di" bpmnElement="downloadAllowListTask">
3348
<dc:Bounds x="265" y="81" width="100" height="80" />
3449
</bpmndi:BPMNShape>
3550
<bpmndi:BPMNShape id="StartEvent_0x5gijn_di" bpmnElement="StartEvent_1">
3651
<dc:Bounds x="179" y="103" width="36" height="36" />
3752
</bpmndi:BPMNShape>
53+
<bpmndi:BPMNShape id="EndEvent_0xd0x8k_di" bpmnElement="EndEvent_0xd0x8k">
54+
<dc:Bounds x="742" y="103" width="36" height="36" />
55+
</bpmndi:BPMNShape>
56+
<bpmndi:BPMNShape id="Activity_1lr62lt_di" bpmnElement="checkAllowListTask">
57+
<dc:Bounds x="430" y="81" width="100" height="80" />
58+
</bpmndi:BPMNShape>
59+
<bpmndi:BPMNShape id="Activity_0bpyxjl_di" bpmnElement="insertAllowListTask">
60+
<dc:Bounds x="590" y="81" width="100" height="80" />
61+
</bpmndi:BPMNShape>
3862
</bpmndi:BPMNPlane>
3963
</bpmndi:BPMNDiagram>
4064
</bpmn:definitions>

0 commit comments

Comments
 (0)