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

Commit f27bb7b

Browse files
committed
1 parent 19aa267 commit f27bb7b

5 files changed

Lines changed: 284 additions & 32 deletions

File tree

codex-process-data-transfer/src/main/java/de/netzwerk_universitaetsmedizin/codex/processes/data_transfer/spring/config/ValidationConfig.java

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,9 @@
5555
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.ValueSetExpansionClient;
5656
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.ValueSetExpansionClientJersey;
5757
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.ValueSetExpansionClientWithFileSystemCache;
58+
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.ValueSetExpansionClientWithModifiers;
5859
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.structure_definition.StructureDefinitionModifier;
60+
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.value_set.ValueSetModifier;
5961
import de.rwh.utils.crypto.CertificateHelper;
6062
import de.rwh.utils.crypto.io.CertificateReader;
6163
import de.rwh.utils.crypto.io.PemIo;
@@ -198,6 +200,12 @@ public static enum TerminologyServerConnectionTestStatus
198200
@Value("${de.netzwerk.universitaetsmedizin.codex.gecco.validation.valueset.expansion.client.verbose:false}")
199201
private boolean valueSetExpansionClientVerbose;
200202

203+
@ProcessDocumentation(description = "List of ValueSet modifier classes, modifiers are executed before atempting to expand a ValueSet and after", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend")
204+
@Value("#{'${de.netzwerk.universitaetsmedizin.codex.gecco.validation.valueset.expansion.modifierClasses:"
205+
+ "de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.value_set.MissingEntriesIncluder"
206+
+ "}'.trim().split('(,[ ]?)|(\\n)')}")
207+
private List<String> valueSetModifierClasses;
208+
201209
@ProcessDocumentation(description = "List of StructureDefinition modifier classes, modifiers are executed before atempting to generate a StructureDefinition snapshot", processNames = "wwwnetzwerk-universitaetsmedizinde_dataSend")
202210
@Value("#{'${de.netzwerk.universitaetsmedizin.codex.gecco.validation.structuredefinition.modifierClasses:"
203211
+ "de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.structure_definition.ClosedTypeSlicingRemover,"
@@ -410,8 +418,29 @@ private ValidationPackageClientJersey validationPackageClientJersey()
410418
@Bean
411419
public ValueSetExpansionClient valueSetExpansionClient()
412420
{
421+
List<ValueSetModifier> modifiers = valueSetModifierClasses.stream().map(this::createValueSetModifier)
422+
.collect(Collectors.toList());
423+
413424
return new ValueSetExpansionClientWithFileSystemCache(valueSetCacheFolder(), fhirContext,
414-
valueSetExpansionClientJersey());
425+
new ValueSetExpansionClientWithModifiers(valueSetExpansionClientJersey(), modifiers));
426+
}
427+
428+
private ValueSetModifier createValueSetModifier(String className)
429+
{
430+
try
431+
{
432+
Class<?> modifierClass = Class.forName(className);
433+
if (ValueSetModifier.class.isAssignableFrom(modifierClass))
434+
return (ValueSetModifier) modifierClass.getConstructor().newInstance();
435+
else
436+
throw new IllegalArgumentException(
437+
"Class " + className + " not compatible with " + ValueSetModifier.class.getName());
438+
}
439+
catch (ClassNotFoundException | InstantiationException | IllegalAccessException | InvocationTargetException
440+
| NoSuchMethodException | SecurityException e)
441+
{
442+
throw new RuntimeException(e);
443+
}
415444
}
416445

417446
@Bean
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation;
2+
3+
import java.io.IOException;
4+
import java.util.ArrayList;
5+
import java.util.Arrays;
6+
import java.util.Collection;
7+
import java.util.List;
8+
import java.util.Objects;
9+
10+
import javax.ws.rs.WebApplicationException;
11+
12+
import org.hl7.fhir.r4.model.CapabilityStatement;
13+
import org.hl7.fhir.r4.model.ValueSet;
14+
import org.springframework.beans.factory.InitializingBean;
15+
16+
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.value_set.MissingEntriesIncluder;
17+
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.value_set.ValueSetModifier;
18+
19+
public class ValueSetExpansionClientWithModifiers implements ValueSetExpansionClient, InitializingBean
20+
{
21+
public static final ValueSetModifier MISSING_ENTRIES_INCLUDER = new MissingEntriesIncluder();
22+
23+
private final ValueSetExpansionClient delegate;
24+
private final List<ValueSetModifier> valueSetModifiers = new ArrayList<>();
25+
26+
public ValueSetExpansionClientWithModifiers(ValueSetExpansionClient delegate)
27+
{
28+
this(delegate, Arrays.asList(MISSING_ENTRIES_INCLUDER));
29+
}
30+
31+
public ValueSetExpansionClientWithModifiers(ValueSetExpansionClient delegate,
32+
Collection<? extends ValueSetModifier> valueSetModifiers)
33+
{
34+
this.delegate = delegate;
35+
36+
if (valueSetModifiers != null)
37+
this.valueSetModifiers.addAll(valueSetModifiers);
38+
}
39+
40+
@Override
41+
public void afterPropertiesSet() throws Exception
42+
{
43+
Objects.requireNonNull(delegate, "delegate");
44+
}
45+
46+
@Override
47+
public ValueSet expand(ValueSet valueSet) throws IOException, WebApplicationException
48+
{
49+
if (valueSet == null)
50+
return null;
51+
52+
for (ValueSetModifier modifier : valueSetModifiers)
53+
valueSet = modifier.modifyPreExpansion(valueSet);
54+
55+
ValueSet expandedValueSet = delegate.expand(valueSet);
56+
57+
for (ValueSetModifier modifier : valueSetModifiers)
58+
expandedValueSet = modifier.modifyPostExpansion(valueSet, expandedValueSet);
59+
60+
return expandedValueSet;
61+
}
62+
63+
@Override
64+
public CapabilityStatement getMetadata() throws WebApplicationException
65+
{
66+
return delegate.getMetadata();
67+
}
68+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.value_set;
2+
3+
import java.util.Set;
4+
import java.util.stream.Collectors;
5+
import java.util.stream.Stream;
6+
7+
import org.hl7.fhir.r4.model.ValueSet;
8+
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
9+
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionContainsComponent;
10+
import org.slf4j.Logger;
11+
import org.slf4j.LoggerFactory;
12+
13+
public class MissingEntriesIncluder implements ValueSetModifier
14+
{
15+
private static final Logger logger = LoggerFactory.getLogger(MissingEntriesIncluder.class);
16+
17+
@Override
18+
public ValueSet modifyPostExpansion(ValueSet vsWithComposition, ValueSet vsWithExpansion)
19+
{
20+
if (vsWithExpansion == null)
21+
return null;
22+
if (!vsWithExpansion.hasExpansion())
23+
return vsWithExpansion;
24+
25+
if (vsWithComposition.hasCompose()
26+
&& vsWithComposition.getCompose().getInclude().stream().anyMatch(ConceptSetComponent::hasConcept))
27+
{
28+
Set<String> expandedEntries = vsWithExpansion.getExpansion().getContains().stream()
29+
.map(c -> toEntry(c.getSystem(), c.getVersion(), c.getCode())).distinct()
30+
.collect(Collectors.toSet());
31+
32+
vsWithComposition.getCompose().getInclude().stream().filter(ConceptSetComponent::hasConcept)
33+
.forEach(include ->
34+
{
35+
String system = include.getSystem();
36+
String version = include.getVersion();
37+
38+
include.getConcept().forEach(concept ->
39+
{
40+
if (!expandedEntries.contains(toEntry(system, version, concept.getCode())))
41+
{
42+
if (version != null)
43+
logger.warn(
44+
"Adding missing concept to ValueSet {}|{}: system: '{}', version: '{}', code: '{}', display: '{}'",
45+
vsWithExpansion.getUrl(), vsWithExpansion.getVersion(), system, version,
46+
concept.getCode(), concept.getDisplay());
47+
else
48+
logger.warn(
49+
"Adding missing concept to ValueSet {}|{}: system: '{}', code: '{}', display: '{}'",
50+
vsWithExpansion.getUrl(), vsWithExpansion.getVersion(), system,
51+
concept.getCode(), concept.getDisplay());
52+
53+
vsWithExpansion.getExpansion()
54+
.addContains(new ValueSetExpansionContainsComponent().setSystem(system)
55+
.setVersion(version).setCode(concept.getCode())
56+
.setDisplay(concept.getDisplay()));
57+
}
58+
});
59+
});
60+
}
61+
62+
return vsWithExpansion;
63+
}
64+
65+
private String toEntry(String system, String version, String code)
66+
{
67+
return Stream.of(system, version, code).filter(e -> e != null).collect(Collectors.joining());
68+
}
69+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.value_set;
2+
3+
import org.hl7.fhir.r4.model.ValueSet;
4+
5+
public interface ValueSetModifier
6+
{
7+
default ValueSet modifyPreExpansion(ValueSet vs)
8+
{
9+
return vs;
10+
}
11+
12+
default ValueSet modifyPostExpansion(ValueSet vsWithComposition, ValueSet vsWithExpansion)
13+
{
14+
return vsWithExpansion;
15+
}
16+
}

0 commit comments

Comments
 (0)