Skip to content
This repository was archived by the owner on Oct 6, 2025. It is now read-only.

Commit e71cc23

Browse files
committed
Merge remote-tracking branch 'origin/release/0.3.2' into main
2 parents 2037952 + c147a47 commit e71cc23

47 files changed

Lines changed: 1280 additions & 569 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

codex-process-data-transfer/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<parent>
99
<groupId>de.netzwerk-universitaetsmedizin.codex</groupId>
1010
<artifactId>codex-processes-ap1</artifactId>
11-
<version>0.3.1</version>
11+
<version>0.3.2</version>
1212
</parent>
1313

1414
<properties>

codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/ConstantsDataTransfer.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public interface ConstantsDataTransfer
2121
String NAMING_SYSTEM_NUM_CODEX_CRR_PSEUDONYM = "http://www.netzwerk-universitaetsmedizin.de/sid/crr-pseudonym";
2222
String NAMING_SYSTEM_NUM_CODEX_BLOOM_FILTER = "http://www.netzwerk-universitaetsmedizin.de/sid/bloom-filter";
2323

24+
String RFC_4122_SYSTEM = "urn:ietf:rfc:4122";
25+
2426
String CODESYSTEM_NUM_CODEX_DATA_TRANSFER = "http://www.netzwerk-universitaetsmedizin.de/fhir/CodeSystem/data-transfer";
2527
String CODESYSTEM_NUM_CODEX_DATA_TRANSFER_VALUE_PATIENT = "patient";
2628
String CODESYSTEM_NUM_CODEX_DATA_TRANSFER_VALUE_PSEUDONYM = "pseudonym";

codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/DataTransferProcessPluginDefinition.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020

2121
public class DataTransferProcessPluginDefinition implements ProcessPluginDefinition
2222
{
23-
public static final String VERSION = "0.3.1";
23+
public static final String VERSION = "0.3.2";
2424

2525
@Override
2626
public String getName()

codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FhirClientFactory.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
import ca.uhn.fhir.context.FhirContext;
2424
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer;
25+
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.client.fhir.FhirClient;
26+
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.client.fhir.FhirClientBuilder;
2527
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.domain.DateWithPrecision;
2628
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.variables.PatientReference;
2729
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.variables.PatientReferenceList;
@@ -39,19 +41,23 @@ public class FhirClientFactory
3941
private final Path searchBundleOverride;
4042
private final String localIdentifierValue;
4143

44+
private final FhirClientBuilder builder;
45+
4246
public FhirClientFactory(HapiFhirClientFactory hapiClientFactory, FhirContext fhirContext,
43-
Path searchBundleOverride, String localIdentifierValue)
47+
Path searchBundleOverride, String localIdentifierValue, FhirClientBuilder builder)
4448
{
4549
this.hapiClientFactory = hapiClientFactory;
4650
this.fhirContext = fhirContext;
4751
this.searchBundleOverride = searchBundleOverride;
4852
this.localIdentifierValue = localIdentifierValue;
53+
54+
this.builder = builder;
4955
}
5056

5157
public FhirClient getFhirClient()
5258
{
5359
if (hapiClientFactory.isConfigured())
54-
return new FhirClientImpl(hapiClientFactory, fhirContext, searchBundleOverride);
60+
return builder.build(fhirContext, hapiClientFactory, searchBundleOverride);
5561
else
5662
return createFhirClientStub();
5763
}

codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClientFactory.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,27 +80,38 @@ public void testConnection()
8080
private final Path trustStorePath;
8181
private final Path certificatePath;
8282
private final Path privateKeyPath;
83-
private final String basicAuthUsername;
84-
private final String basicAuthPassword;
83+
8584
private final String fttpServerBase;
85+
private final String fttpBasicAuthUsername;
86+
private final String fttpBasicAuthPassword;
87+
8688
private final String fttpApiKey;
8789
private final String fttpStudy;
8890
private final String fttpTarget;
8991

90-
public FttpClientFactory(Path trustStorePath, Path certificatePath, Path privateKeyPath, String basicAuthUsername,
91-
String basicAuthPassword, String fttpServerBase, String fttpApiKey, String fttpStudy, String fttpTarget)
92+
private final String proxySchemeHostPort;
93+
private final String proxyUsername;
94+
private final String proxyPassword;
95+
96+
public FttpClientFactory(Path trustStorePath, Path certificatePath, Path privateKeyPath,
97+
String fttpBasicAuthUsername, String fttpBasicAuthPassword, String fttpServerBase, String fttpApiKey,
98+
String fttpStudy, String fttpTarget, String proxySchemeHostPort, String proxyUsername, String proxyPassword)
9299
{
93100
this.trustStorePath = trustStorePath;
94101
this.certificatePath = certificatePath;
95102
this.privateKeyPath = privateKeyPath;
96103

97-
this.basicAuthUsername = basicAuthUsername;
98-
this.basicAuthPassword = basicAuthPassword;
104+
this.fttpBasicAuthUsername = fttpBasicAuthUsername;
105+
this.fttpBasicAuthPassword = fttpBasicAuthPassword;
99106

100107
this.fttpServerBase = fttpServerBase;
101108
this.fttpApiKey = fttpApiKey;
102109
this.fttpStudy = fttpStudy;
103110
this.fttpTarget = fttpTarget;
111+
112+
this.proxySchemeHostPort = proxySchemeHostPort;
113+
this.proxyUsername = proxyUsername;
114+
this.proxyPassword = proxyPassword;
104115
}
105116

106117
@EventListener({ ContextRefreshedEvent.class })
@@ -144,8 +155,8 @@ protected FttpClient createFttpClient()
144155
logger.debug("Creating key-store from {} and {}", certificatePath.toString(), privateKeyPath.toString());
145156
KeyStore keyStore = readKeyStore(certificatePath, privateKeyPath, keyStorePassword);
146157

147-
return new FttpClientImpl(trustStore, keyStore, keyStorePassword, basicAuthUsername, basicAuthPassword,
148-
fttpServerBase, fttpApiKey, fttpStudy, fttpTarget);
158+
return new FttpClientImpl(trustStore, keyStore, keyStorePassword, fttpBasicAuthUsername, fttpBasicAuthPassword,
159+
fttpServerBase, fttpApiKey, fttpStudy, fttpTarget, proxySchemeHostPort, proxyUsername, proxyPassword);
149160
}
150161

151162
private KeyStore readTrustStore(Path trustPath)

codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/FttpClientImpl.java

Lines changed: 43 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
import static de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.ConstantsDataTransfer.PSEUDONYM_PATTERN_STRING;
44

5+
import java.net.MalformedURLException;
6+
import java.net.URL;
57
import java.security.KeyStore;
68
import java.util.Objects;
79
import java.util.Optional;
810
import java.util.regex.Matcher;
911
import java.util.regex.Pattern;
1012

13+
import org.apache.commons.lang3.StringUtils;
1114
import org.hl7.fhir.r4.model.Base64BinaryType;
1215
import org.hl7.fhir.r4.model.CapabilityStatement;
1316
import org.hl7.fhir.r4.model.Identifier;
@@ -34,23 +37,32 @@ public class FttpClientImpl implements FttpClient, InitializingBean
3437

3538
private final IRestfulClientFactory clientFactory;
3639

37-
private final String basicAuthUsername;
38-
private final String basicAuthPassword;
39-
4040
private final String fttpServerBase;
41+
private final String fttpBasicAuthUsername;
42+
private final String fttpBasicAuthPassword;
43+
4144
private final String fttpStudy;
4245
private final String fttpTarget;
4346
private final String fttpApiKey;
4447

45-
public FttpClientImpl(KeyStore trustStore, KeyStore keyStore, char[] keyStorePassword, String basicAuthUsername,
46-
String basicAuthPassword, String fttpServerBase, String fttpApiKey, String fttpStudy, String fttpTarget)
48+
private final String proxySchemeHostPort;
49+
private final String proxyUsername;
50+
private final String proxyPassword;
51+
52+
public FttpClientImpl(KeyStore trustStore, KeyStore keyStore, char[] keyStorePassword, String fttpBasicAuthUsername,
53+
String fttpBasicAuthPassword, String fttpServerBase, String fttpApiKey, String fttpStudy, String fttpTarget,
54+
String proxySchemeHostPort, String proxyUsername, String proxyPassword)
4755
{
48-
this.basicAuthUsername = basicAuthUsername;
49-
this.basicAuthPassword = basicAuthPassword;
56+
this.proxySchemeHostPort = proxySchemeHostPort;
57+
this.proxyUsername = proxyUsername;
58+
this.proxyPassword = proxyPassword;
5059

5160
clientFactory = createClientFactory(trustStore, keyStore, keyStorePassword);
5261

5362
this.fttpServerBase = fttpServerBase;
63+
this.fttpBasicAuthUsername = fttpBasicAuthUsername;
64+
this.fttpBasicAuthPassword = fttpBasicAuthPassword;
65+
5466
this.fttpApiKey = fttpApiKey;
5567
this.fttpStudy = fttpStudy;
5668
this.fttpTarget = fttpTarget;
@@ -67,11 +79,32 @@ protected ApacheRestfulClientFactoryWithTlsConfig createClientFactory(KeyStore t
6779
ApacheRestfulClientFactoryWithTlsConfig hapiClientFactory = new ApacheRestfulClientFactoryWithTlsConfig(
6880
fhirContext, trustStore, keyStore, keyStorePassword);
6981
hapiClientFactory.setServerValidationMode(ServerValidationModeEnum.NEVER);
82+
configureProxy(hapiClientFactory);
7083

7184
fhirContext.setRestfulClientFactory(hapiClientFactory);
7285
return hapiClientFactory;
7386
}
7487

88+
private void configureProxy(ApacheRestfulClientFactoryWithTlsConfig clientFactory)
89+
{
90+
if (StringUtils.isNotBlank(proxySchemeHostPort))
91+
{
92+
try
93+
{
94+
URL url = new URL(proxySchemeHostPort);
95+
clientFactory.setProxy(url.getHost(), url.getPort());
96+
clientFactory.setProxyCredentials(proxyUsername, proxyPassword);
97+
98+
logger.info("Using proxy for fTTP connection with {host: {}, port: {}, username: {}}", url.getHost(),
99+
url.getPort(), proxyUsername);
100+
}
101+
catch (MalformedURLException e)
102+
{
103+
logger.error("Could not configure proxy", e);
104+
}
105+
}
106+
}
107+
75108
@Override
76109
public void afterPropertiesSet() throws Exception
77110
{
@@ -139,7 +172,7 @@ public Optional<String> getDicPseudonym(String bloomFilter)
139172
.withParameters(createParametersForBfWorkflow(bloomFilter)).accept(Constants.CT_FHIR_XML_NEW)
140173
.encoded(EncodingEnum.XML).execute();
141174

142-
return getPseudonym(parameters);
175+
return getPseudonym(parameters).map(p -> fttpTarget + "/" + p);
143176
}
144177
catch (Exception e)
145178
{
@@ -198,13 +231,13 @@ private IGenericClient createGenericClient()
198231
client.registerInterceptor(new LoggingInterceptor());
199232

200233
if (configuredWithBasicAuth())
201-
client.registerInterceptor(new BasicAuthInterceptor(basicAuthUsername, basicAuthPassword));
234+
client.registerInterceptor(new BasicAuthInterceptor(fttpBasicAuthUsername, fttpBasicAuthPassword));
202235

203236
return client;
204237
}
205238

206239
private boolean configuredWithBasicAuth()
207240
{
208-
return basicAuthUsername != null && basicAuthPassword != null;
241+
return fttpBasicAuthUsername != null && fttpBasicAuthPassword != null;
209242
}
210243
}

codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/client/HapiFhirClientFactory.java

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ public class HapiFhirClientFactory
4747
private final String basicAuthUsername;
4848
private final String basicAuthPassword;
4949
private final String bearerToken;
50-
private final boolean supportsIdentifierReferenceSearch;
5150

5251
private final ApacheRestfulClientFactory clientFactory;
5352

@@ -62,10 +61,9 @@ public class HapiFhirClientFactory
6261
* may be <code>null</code>
6362
* @param bearerToken
6463
* may be <code>null</code>
65-
* @param supportsIdentifierReferenceSearch
6664
*/
6765
public HapiFhirClientFactory(FhirContext fhirContext, String serverBase, String basicAuthUsername,
68-
String basicAuthPassword, String bearerToken, boolean supportsIdentifierReferenceSearch)
66+
String basicAuthPassword, String bearerToken)
6967
{
7068
if (fhirContext != null)
7169
this.fhirContext = fhirContext;
@@ -76,7 +74,6 @@ public HapiFhirClientFactory(FhirContext fhirContext, String serverBase, String
7674
this.basicAuthUsername = basicAuthUsername;
7775
this.basicAuthPassword = basicAuthPassword;
7876
this.bearerToken = bearerToken;
79-
this.supportsIdentifierReferenceSearch = supportsIdentifierReferenceSearch;
8077

8178
if (isConfigured())
8279
{
@@ -87,11 +84,6 @@ public HapiFhirClientFactory(FhirContext fhirContext, String serverBase, String
8784
clientFactory = null;
8885
}
8986

90-
public boolean supportsIdentifierReferenceSearch()
91-
{
92-
return supportsIdentifierReferenceSearch;
93-
}
94-
9587
protected boolean isConfigured()
9688
{
9789
return serverBase != null && !serverBase.isEmpty();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.client;
2+
3+
import java.util.function.BiConsumer;
4+
import java.util.stream.Collectors;
5+
import java.util.stream.Stream;
6+
7+
import org.hl7.fhir.r4.model.OperationOutcome;
8+
import org.hl7.fhir.r4.model.OperationOutcome.IssueSeverity;
9+
import org.slf4j.Logger;
10+
11+
public class OutcomeLogger
12+
{
13+
private final Logger logger;
14+
15+
public OutcomeLogger(Logger logger)
16+
{
17+
this.logger = logger;
18+
}
19+
20+
public void logOutcome(OperationOutcome outcome)
21+
{
22+
outcome.getIssue().forEach(issue ->
23+
{
24+
String display = issue.getCode() == null ? null : issue.getCode().getDisplay();
25+
String details = issue.getDetails() == null ? null : issue.getDetails().getText();
26+
String diagnostics = issue.getDiagnostics();
27+
28+
String message = Stream.of(display, details, diagnostics).filter(s -> s != null && !s.isBlank())
29+
.collect(Collectors.joining(" "));
30+
31+
getLoggerForSeverity(issue.getSeverity(), logger).accept("Issue: {}", message);
32+
});
33+
}
34+
35+
private BiConsumer<String, Object> getLoggerForSeverity(IssueSeverity severity, Logger logger)
36+
{
37+
if (severity != null)
38+
{
39+
switch (severity)
40+
{
41+
case ERROR:
42+
case FATAL:
43+
return logger::error;
44+
case WARNING:
45+
return logger::warn;
46+
case NULL:
47+
case INFORMATION:
48+
default:
49+
return logger::info;
50+
}
51+
}
52+
53+
return logger::info;
54+
}
55+
}

0 commit comments

Comments
 (0)