Skip to content

Commit 9122ac8

Browse files
committed
Merge remote-tracking branch 'origin/release/0.2.0' into main
2 parents bedf6f6 + 4dec680 commit 9122ac8

File tree

9 files changed

+157
-32
lines changed

9 files changed

+157
-32
lines changed

README.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,19 @@
55

66
### Run
77
By default the validator is configured to expand value-sets via https://ontoserver.mii-termserv.de and thus requires a client certificate to be configured.
8+
The validator also needs to be configured with a list of implementation guide packages (name|version) to validate against.
9+
810

911
Create `application.properties` file with the following content in your execution directory:
1012

1113
```
12-
dev.dsf.validation.valueset.expansion.client.authentication.certificate:certificate.pem
13-
dev.dsf.validation.valueset.expansion.client.authentication.certificate.private.key.password:private_key_password
14-
dev.dsf.validation.valueset.expansion.client.authentication.certificate.private.key:privatekey.pem
14+
dev.dsf.validation.valueset.expansion.client.authentication.certificate: certificate.pem
15+
dev.dsf.validation.valueset.expansion.client.authentication.certificate.private.key.password: private_key_password
16+
dev.dsf.validation.valueset.expansion.client.authentication.certificate.private.key: privatekey.pem
17+
dev.dsf.validation.package: \
18+
de.medizininformatikinitiative.kerndatensatz.laborbefund|2025.0.2, \
19+
de.medizininformatikinitiative.kerndatensatz.prozedur|2025.0.0, \
20+
de.medizininformatikinitiative.kerndatensatz.diagnose|2025.0.0
1521
```
1622

17-
`java -jar target/dsf-fhir-validator.jar fhir-resource-to-validate.xml` (.json supported also)
23+
`java -jar target/dsf-fhir-validator.jar fhir-resource-to-validate.xml` (.json also supported)

pom.xml

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

77
<groupId>dev.dsf</groupId>
88
<artifactId>dsf-fhir-validator</artifactId>
9-
<version>0.1.0</version>
9+
<version>0.2.0</version>
1010

1111
<properties>
1212
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package dev.dsf.fhir.validator.implementation_guide;
2+
3+
import java.util.Comparator;
4+
import java.util.Map;
5+
import java.util.Map.Entry;
6+
import java.util.Optional;
7+
import java.util.regex.Matcher;
8+
import java.util.regex.Pattern;
9+
10+
import com.fasterxml.jackson.annotation.JsonCreator;
11+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
12+
import com.fasterxml.jackson.annotation.JsonProperty;
13+
14+
@JsonIgnoreProperties(ignoreUnknown = true)
15+
public record PackageVersions(@JsonProperty("_id") String id, @JsonProperty("name") String name,
16+
@JsonProperty("description") String description, @JsonProperty("dist-tags") PackageVersionsDistTags distTags,
17+
@JsonProperty("versions") Map<String, PackageVersionsVersions> versions)
18+
{
19+
@JsonIgnoreProperties(ignoreUnknown = true)
20+
public record PackageVersionsDistTags(@JsonProperty("latest") String latest)
21+
{
22+
@JsonCreator
23+
public PackageVersionsDistTags(@JsonProperty("latest") String latest)
24+
{
25+
this.latest = latest;
26+
}
27+
}
28+
29+
@JsonIgnoreProperties(ignoreUnknown = true)
30+
public record PackageVersionsVersions(@JsonProperty("name") String name,
31+
@JsonProperty("description") String description, @JsonProperty("fhirVersion") String fhirVersion,
32+
@JsonProperty("version") String version, @JsonProperty("dist") PackageVersionsVersionsDist dist,
33+
@JsonProperty("url") String url, @JsonProperty("unlisted") String unlisted)
34+
{
35+
@JsonIgnoreProperties(ignoreUnknown = true)
36+
public record PackageVersionsVersionsDist(@JsonProperty("shasum") String shasum,
37+
@JsonProperty("tarball") String tarball)
38+
{
39+
@JsonCreator
40+
public PackageVersionsVersionsDist(@JsonProperty("shasum") String shasum,
41+
@JsonProperty("tarball") String tarball)
42+
{
43+
this.shasum = shasum;
44+
this.tarball = tarball;
45+
}
46+
}
47+
48+
@JsonCreator
49+
public PackageVersionsVersions(@JsonProperty("name") String name,
50+
@JsonProperty("description") String description, @JsonProperty("fhirVersion") String fhirVersion,
51+
@JsonProperty("version") String version, @JsonProperty("dist") PackageVersionsVersionsDist dist,
52+
@JsonProperty("url") String url, @JsonProperty("unlisted") String unlisted)
53+
{
54+
this.name = name;
55+
this.description = description;
56+
this.fhirVersion = fhirVersion;
57+
this.version = version;
58+
this.dist = dist;
59+
this.url = url;
60+
this.unlisted = unlisted;
61+
}
62+
}
63+
64+
public PackageVersions(@JsonProperty("_id") String id, @JsonProperty("name") String name,
65+
@JsonProperty("description") String description,
66+
@JsonProperty("dist-tags") PackageVersionsDistTags distTags,
67+
@JsonProperty("versions") Map<String, PackageVersionsVersions> versions)
68+
{
69+
this.id = id;
70+
this.name = name;
71+
this.description = description;
72+
this.distTags = distTags;
73+
this.versions = versions;
74+
}
75+
76+
public Optional<String> getLatest(String versionPrefix)
77+
{
78+
if (!versionPrefix.matches("\\d+\\.\\d+\\."))
79+
throw new IllegalArgumentException("versionPrefix must match \\d+\\.\\d+\\.");
80+
81+
return versions.entrySet().stream()
82+
.filter(e -> e.getKey() != null && e.getKey().matches(versionPrefix + "\\d+")).map(Entry::getKey)
83+
.sorted(Comparator.comparingInt((String v) ->
84+
{
85+
try
86+
{
87+
Pattern p = Pattern.compile(versionPrefix + "(\\d+)");
88+
Matcher matcher = p.matcher(v);
89+
if (matcher.matches())
90+
return Integer.parseInt(matcher.group(1));
91+
}
92+
catch (NumberFormatException e)
93+
{
94+
}
95+
96+
return -1;
97+
}).reversed()).findFirst();
98+
}
99+
}

src/main/java/dev/dsf/fhir/validator/implementation_guide/ValidationPackageClient.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,12 @@ default ValidationPackage download(String name, String version) throws IOExcepti
2828
* @throws WebApplicationException
2929
*/
3030
ValidationPackage download(ValidationPackageIdentifier identifier) throws IOException, WebApplicationException;
31+
32+
/**
33+
* @param name
34+
* not <code>null</code>
35+
* @return package versions
36+
* @throws WebApplicationException
37+
*/
38+
PackageVersions list(String name) throws WebApplicationException;
3139
}

src/main/java/dev/dsf/fhir/validator/implementation_guide/ValidationPackageClientJersey.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ private WebTarget getResource()
9393

9494
@Override
9595
public ValidationPackage download(ValidationPackageIdentifier identifier)
96-
throws IOException, WebApplicationException
96+
throws WebApplicationException, IOException
9797
{
9898
Objects.requireNonNull(identifier, "identifier");
9999

@@ -103,4 +103,12 @@ public ValidationPackage download(ValidationPackageIdentifier identifier)
103103
return ValidationPackage.from(identifier.getName(), identifier.getVersion(), in);
104104
}
105105
}
106+
107+
@Override
108+
public PackageVersions list(String name) throws WebApplicationException
109+
{
110+
Objects.requireNonNull(name, "name");
111+
112+
return getResource().path(name).request("application/json").get(PackageVersions.class);
113+
}
106114
}

src/main/java/dev/dsf/fhir/validator/implementation_guide/ValidationPackageClientWithFileSystemCache.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,4 +76,12 @@ public ValidationPackage download(ValidationPackageIdentifier identifier)
7676
return writeToCache(delegate.download(identifier), p -> p.getIdentifier().toString(),
7777
p -> "validation package", mapper::writeValue);
7878
}
79+
80+
@Override
81+
public PackageVersions list(String name) throws WebApplicationException
82+
{
83+
Objects.requireNonNull(name, "name");
84+
85+
return delegate.list(name);
86+
}
7987
}

src/main/java/dev/dsf/fhir/validator/implementation_guide/ValidationPackageManagerImpl.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.List;
88
import java.util.Map;
99
import java.util.Objects;
10+
import java.util.Optional;
1011

1112
import org.slf4j.Logger;
1213
import org.slf4j.LoggerFactory;
@@ -111,6 +112,17 @@ else if (noDownloadPackages.contains(identifier))
111112

112113
private ValidationPackage downloadAndHandleException(ValidationPackageIdentifier identifier)
113114
{
115+
if (identifier.getVersion().matches("\\d+\\.\\d+\\.x"))
116+
{
117+
String versoinPrefix = identifier.getVersion().substring(0, identifier.getVersion().length() - 1);
118+
119+
PackageVersions versions = validationPackageClient.list(identifier.getName());
120+
Optional<String> latest = versions.getLatest(versoinPrefix);
121+
122+
if (latest.isPresent())
123+
identifier = new ValidationPackageIdentifier(identifier.getName(), latest.get());
124+
}
125+
114126
try
115127
{
116128
logger.debug("Downloading validation package {}", identifier);

src/main/java/dev/dsf/fhir/validator/main/ValidationConfig.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ public static enum TerminologyServerConnectionTestStatus
7575
@Value("${dev.dsf.validation:true}")
7676
private boolean validationEnabled;
7777

78-
@Value("#{'${dev.dsf.validation.package:de.medizininformatikinitiative.kerndatensatz.laborbefund|2025.0.2}'.trim().split('(,[ ]?)|(\\n)')}")
78+
@Value("#{'${dev.dsf.validation.package:}'.trim().split('(,[ ]?)|(\\n)')}")
7979
private List<String> validationPackages;
8080

8181
@Value("#{'${dev.dsf.validation.package.noDownload:}'.trim().split('(,[ ]?)|(\\n)')}")
@@ -154,7 +154,6 @@ public static enum TerminologyServerConnectionTestStatus
154154

155155
@Value("#{'${dev.dsf.validation.structuredefinition.modifierClasses:"
156156
+ "dev.dsf.fhir.validator.structure_definition.ClosedTypeSlicingRemover,"
157-
+ "dev.dsf.fhir.validator.structure_definition.IdentifierRemover,"
158157
+ "dev.dsf.fhir.validator.structure_definition.SliceMinFixer" + "}'.trim().split('(,[ ]?)|(\\n)')}")
159158
private List<String> structureDefinitionModifierClasses;
160159

@@ -488,9 +487,15 @@ public TerminologyServerConnectionTestStatus testConnectionToTerminologyServer()
488487
@Bean
489488
public List<ValidationPackageIdentifier> validationPackageIdentifiers()
490489
{
491-
if (validationPackages == null || validationPackages.isEmpty())
492-
throw new IllegalArgumentException("Validation packages not specified");
490+
if (validationPackages == null || validationPackages.isEmpty()
491+
|| validationPackages.stream().filter(Predicate.not(String::isBlank)).count() == 0)
492+
{
493+
logger.warn(
494+
"Validation packages not specified, define at least one package via config parameter 'dev.dsf.validation.package' in the form 'name|version[, name|version]'");
495+
return List.of();
496+
}
493497

494-
return validationPackages.stream().map(ValidationPackageIdentifier::fromString).toList();
498+
return validationPackages.stream().filter(Predicate.not(String::isBlank))
499+
.map(ValidationPackageIdentifier::fromString).toList();
495500
}
496501
}

src/main/java/dev/dsf/fhir/validator/structure_definition/SnapshotGeneratorImpl.java

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,10 @@
22

33
import java.util.ArrayList;
44
import java.util.List;
5-
import java.util.Optional;
65

76
import org.hl7.fhir.r4.conformance.ProfileUtilities;
87
import org.hl7.fhir.r4.context.IWorkerContext;
98
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
10-
import org.hl7.fhir.r4.model.ElementDefinition;
11-
import org.hl7.fhir.r4.model.StringType;
129
import org.hl7.fhir.r4.model.StructureDefinition;
1310
import org.hl7.fhir.utilities.validation.ValidationMessage;
1411
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
@@ -80,24 +77,6 @@ public SnapshotWithValidationMessages generateSnapshot(StructureDefinition diffe
8077
m.getLine(), m.getMessage()));
8178
}
8279

83-
// FIXME workaround HAPI ProfileUtilities bug
84-
if ("http://dsf.dev/fhir/StructureDefinition/task-base".equals(differential.getBaseDefinition()))
85-
{
86-
Optional<ElementDefinition> taskInputValueX = differential.getSnapshot().getElement().stream()
87-
.filter(e -> "Task.input.value[x]".equals(e.getId()) && e.getFixed() instanceof StringType s
88-
&& s.getValue() != null)
89-
.findFirst();
90-
91-
taskInputValueX.ifPresent(e ->
92-
{
93-
logger.warn("Removing fixedString value '{}' from StructureDefinition '{}|{}' snapshot element '{}'",
94-
((StringType) e.getFixed()).getValue(), differential.getUrl(), differential.getVersion(),
95-
e.getId());
96-
97-
e.setFixed(null);
98-
});
99-
}
100-
10180
return new SnapshotWithValidationMessages(differential, messages);
10281
}
10382
}

0 commit comments

Comments
 (0)