1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.openehealth.ipf.commons.ihe.fhir.support;
18
19
20 import ca.uhn.fhir.rest.api.MethodOutcome;
21 import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
22 import ca.uhn.fhir.rest.param.TokenParam;
23 import org.hl7.fhir.dstu3.model.Reference;
24 import org.hl7.fhir.instance.model.api.IBaseCoding;
25 import org.hl7.fhir.instance.model.api.IDomainResource;
26 import org.hl7.fhir.instance.model.api.IIdType;
27 import org.openehealth.ipf.commons.audit.AuditContext;
28 import org.openehealth.ipf.commons.audit.codes.EventOutcomeIndicator;
29 import org.openehealth.ipf.commons.audit.model.AuditMessage;
30 import org.openehealth.ipf.commons.ihe.fhir.Constants;
31 import org.openehealth.ipf.commons.ihe.fhir.FhirSearchParameters;
32 import org.openehealth.ipf.commons.ihe.fhir.RequestDetailProvider;
33 import org.openehealth.ipf.commons.ihe.fhir.audit.GenericFhirAuditDataset;
34 import org.openehealth.ipf.commons.ihe.fhir.audit.events.GenericFhirAuditMessageBuilder;
35
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Optional;
39 import java.util.function.Function;
40 import java.util.stream.Collectors;
41
42 import static java.util.Objects.requireNonNull;
43 import static org.openehealth.ipf.commons.ihe.fhir.Constants.*;
44
45
46
47
48
49
50
51 public class GenericFhirAuditStrategy<T extends IDomainResource> extends FhirAuditStrategy<GenericFhirAuditDataset> {
52
53 private Function<T, Optional<Reference>> patientIdExtractor;
54
55
56
57
58
59 public GenericFhirAuditStrategy(boolean serverSide, Function<T, Optional<Reference>> patientIdExtractor) {
60 super(serverSide);
61 this.patientIdExtractor = requireNonNull(patientIdExtractor);
62 }
63
64 @Override
65 public GenericFhirAuditDataset createAuditDataset() {
66 return new GenericFhirAuditDataset(isServerSide());
67 }
68
69 @Override
70 public GenericFhirAuditDataset enrichAuditDatasetFromRequest(GenericFhirAuditDataset auditDataset, Object request, Map<String, Object> parameters) {
71 super.enrichAuditDatasetFromRequest(auditDataset, request, parameters);
72
73 String resourceType = (String) parameters.get(FHIR_RESOURCE_TYPE_HEADER);
74 if (resourceType == null && RequestDetailProvider.getRequestDetails() != null) {
75 resourceType = RequestDetailProvider.getRequestDetails().getResourceName();
76 }
77 auditDataset.setAffectedResourceType(resourceType);
78
79 RestOperationTypeEnum operation = (RestOperationTypeEnum) parameters.get(FHIR_OPERATION_HEADER);
80 if (operation == null && RequestDetailProvider.getRequestDetails() != null) {
81 operation = RequestDetailProvider.getRequestDetails().getRestOperationType();
82 }
83 auditDataset.setOperation(operation);
84
85
86 if (request instanceof IDomainResource) {
87 addResourceData(auditDataset, (T) request);
88 } else if (request instanceof IIdType) {
89 auditDataset.setResourceId((IIdType) request);
90 }
91
92 if (parameters.containsKey(Constants.FHIR_REQUEST_PARAMETERS)) {
93 String query = (String) parameters.get(HTTP_QUERY);
94 auditDataset.setQueryString(query);
95
96 FhirSearchParameters searchParameter = (FhirSearchParameters) parameters.get(Constants.FHIR_REQUEST_PARAMETERS);
97 if (searchParameter != null) {
98 List<TokenParam> tokenParams = searchParameter.getPatientIdParam();
99 if (tokenParams != null) {
100 auditDataset.getPatientIds().addAll(
101 tokenParams.stream()
102 .map(t -> t.getValueAsQueryToken(searchParameter.getFhirContext()))
103 .collect(Collectors.toList()));
104 }
105 }
106 }
107 return auditDataset;
108 }
109
110 @Override
111 public boolean enrichAuditDatasetFromResponse(GenericFhirAuditDataset auditDataset, Object response, AuditContext auditContext) {
112
113 if (response instanceof IDomainResource) {
114 addResourceData(auditDataset, (T) response);
115 }
116 if (response instanceof MethodOutcome) {
117 MethodOutcome methodOutcome = (MethodOutcome) response;
118 if (methodOutcome.getCreated() != null && methodOutcome.getCreated()) {
119 auditDataset.setEventOutcomeIndicator(EventOutcomeIndicator.Success);
120 }
121 if (methodOutcome.getOperationOutcome() != null) {
122 super.enrichAuditDatasetFromResponse(auditDataset, methodOutcome.getOperationOutcome(), auditContext);
123 } else {
124 auditDataset.setEventOutcomeIndicator(EventOutcomeIndicator.Success);
125 }
126 if (methodOutcome.getResource() != null && methodOutcome.getResource() instanceof IDomainResource) {
127 addResourceData(auditDataset, (T) methodOutcome.getResource());
128 } else if (methodOutcome.getId() != null) {
129 auditDataset.setResourceId(methodOutcome.getId());
130 if (methodOutcome.getId().hasResourceType()) {
131 auditDataset.setAffectedResourceType(methodOutcome.getId().getResourceType());
132 }
133 }
134 }
135 return super.enrichAuditDatasetFromResponse(auditDataset, response, auditContext);
136 }
137
138 @Override
139 public AuditMessage[] makeAuditMessage(AuditContext auditContext, GenericFhirAuditDataset auditDataset) {
140 GenericFhirAuditMessageBuilder builder = new GenericFhirAuditMessageBuilder(auditContext, auditDataset)
141 .addPatients(auditDataset);
142 if (auditDataset.getAffectedResourceType() != null && auditDataset.getQueryString() != null) {
143 builder.addQueryParticipantObject(auditDataset);
144 } else if (auditDataset.getResourceId() != null) {
145 builder.addResourceParticipantObject(auditDataset);
146 }
147 return builder.getMessages();
148
149 }
150
151 private void addResourceData(GenericFhirAuditDataset auditDataset, T resource) {
152 auditDataset.setResourceId(resource.getIdElement());
153 if (resource.getIdElement().hasResourceType()) {
154 auditDataset.setAffectedResourceType(resource.getIdElement().getResourceType());
155 }
156 patientIdExtractor.apply(resource).ifPresent(patient ->
157 auditDataset.getPatientIds().add(patient.getResource() != null ?
158 patient.getResource().getIdElement().toUnqualifiedVersionless().getValue() :
159 patient.getReference()));
160
161 List<? extends IBaseCoding> securityLabels = resource.getMeta().getSecurity();
162 if (!securityLabels.isEmpty()) {
163 auditDataset.setSecurityLabel(securityLabels.get(0).getCode());
164 }
165 }
166 }