Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: CI Build
on:
pull_request:
push:
branches:
- main

jobs:
build:
permissions:
contents: read # checkout
actions: read # needed for upload‑artifact

runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v6

- name: Setup Java
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
cache: 'maven'

- name: Build with Maven
run: mvn clean install -DskipTests --no-transfer-progress

- name: Run Tests
run: |
mvn verify \
-Dsurefire.reportFormat=xml \
--no-transfer-progress

- name: Upload JUnit reports
if: always()
uses: actions/upload-artifact@v7
with:
name: junit-reports
path: target/surefire-reports/*.xml

- name: Upload JaCoCo coverage
if: always()
uses: actions/upload-artifact@v7
with:
name: jacoco-report
path: target/site/jacoco/**
6 changes: 1 addition & 5 deletions cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>referencevalidator</artifactId>
<groupId>de.gematik.refv</groupId>
<version>2.15.0</version>
<version>3.0.0-SNAPSHOT</version>
</parent>
<properties>
<integrationtest.folder>${basedir}/target/test-classes/pluginloader-integration-test</integrationtest.folder>
Expand Down Expand Up @@ -107,10 +107,6 @@
<groupId>info.picocli</groupId>
<artifactId>picocli</artifactId>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Expand Down
10 changes: 9 additions & 1 deletion commons/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>referencevalidator</artifactId>
<groupId>de.gematik.refv</groupId>
<version>2.15.0</version>
<version>3.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down Expand Up @@ -61,5 +61,13 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-caching-caffeine</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
</dependencies>
</project>
4 changes: 2 additions & 2 deletions commons/src/main/java/de/gematik/refv/commons/Profile.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@ public static Profile parse(String canonical) {
String[] splittedString = canonical.split("\\|");
if (splittedString.length < 2) {
return new Profile(canonical, splittedString[0], null);
} else {
return new Profile(canonical, splittedString[0], splittedString[1]);
}

return new Profile(canonical, splittedString[0], splittedString[1]);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,12 @@ public Profile findFirstSupportedProfileWithExistingConfiguration(List<String> p
profiles.stream()
.map(Profile::parse)
.filter(profile -> getSupportedProfileConfiguration(profile).isPresent())
.collect(Collectors.toList());
.toList();
if (supportedProfilesFound.isEmpty()) return null;
if (supportedProfilesFound.size() > 1)
log.warn(
"Multiple supported profiles found. Selecting the first one for further processing: {}",
supportedProfilesFound.get(0));
return supportedProfilesFound.get(0);
supportedProfilesFound.getFirst());
return supportedProfilesFound.getFirst();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,10 @@ class BundleValidationModule implements IValidatorModule {
@Override
public void validateResource(IValidationContext<IBaseResource> iValidationContext) {
var resource = iValidationContext.getResource();
if (!(resource instanceof Bundle)) return;
if (!(resource instanceof Bundle bundle)) {
return;
}

var bundle = (Bundle) resource;
var i = 0;
for (var entry : bundle.getEntry()) {
String fullUrl = entry.getFullUrl();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,15 @@ public ValidationResult validate(
ValidationResult result;
var configuration = resourceProvider.getConfiguration();

if (!validateEncoding(resourceBody, configuration, validationOptions))
if (!validateEncoding(resourceBody, configuration, validationOptions)) {
result =
ValidationResult.createInstance(
ResultSeverityEnum.ERROR,
ERR_REFV_WRONG_ENCODING,
String.format(
"Wrong instance encoding. Allowed encodings: %s",
String.join(",", getAcceptedEncodings(configuration, validationOptions))));
else {
} else {

List<String> allReferencedProfilesInResource =
referencedProfileLocator.getAllReferencedProfilesInResource(resourceBody);
Expand All @@ -131,21 +131,23 @@ && noneReferencedProfileMatches(
var userDefinedProfile =
validationOptions
.getProfiles()
.get(0); // Only one user defined profile is supported at the moment
.getFirst(); // Only one user defined profile is supported at the moment
log.warn("Profile for validation has been passed by user: " + userDefinedProfile);
profileForValidation =
configuration.findFirstSupportedProfileWithExistingConfiguration(
List.of(userDefinedProfile));
} else if (!allReferencedProfilesInResource.isEmpty())
} else if (!allReferencedProfilesInResource.isEmpty()) {
profileForValidation =
configuration.findFirstSupportedProfileWithExistingConfiguration(
allReferencedProfilesInResource);
else
} else {
throw new IllegalArgumentException(
"FHIR resources without a referenced profile are currently unsupported. Please provide a profile parameter or a profile in the resource meta.profile element.");
}

if (profileForValidation == null)
if (profileForValidation == null) {
throw new UnsupportedProfileException(allReferencedProfilesInResource);
}

result =
validateResource(
Expand Down Expand Up @@ -179,11 +181,12 @@ private ValidationResult validateResource(

var profileConfigurationOptional =
configuration.getSupportedProfileConfiguration(profileForValidation);
if (profileConfigurationOptional.isEmpty())
if (profileConfigurationOptional.isEmpty()) {
// Profile is listed among supported profiles, but there are no dependency lists defined -->
// corrupted module configuration
throw new IllegalStateException(
String.format("Could not retrieve profile configuration for %s", profileForValidation));
}

ProfileConfiguration profileConfiguration = profileConfigurationOptional.get();

Expand Down Expand Up @@ -296,15 +299,19 @@ private boolean validateEncoding(
de.gematik.refv.commons.validation.ValidationOptions validationOptions) {
List<String> acceptedEncodings = getAcceptedEncodings(configuration, validationOptions);

if (acceptedEncodings.isEmpty()) return true;
if (acceptedEncodings.isEmpty()) {
return true;
}

EncodingEnum encoding = EncodingEnum.detectEncodingNoDefault(resourceBody);

if (acceptedEncodings.contains(Constants.FORMAT_XML) && encoding == EncodingEnum.XML)
if (acceptedEncodings.contains(Constants.FORMAT_XML) && encoding == EncodingEnum.XML) {
return true;
}

if (acceptedEncodings.contains(Constants.FORMAT_JSON) && encoding == EncodingEnum.JSON)
if (acceptedEncodings.contains(Constants.FORMAT_JSON) && encoding == EncodingEnum.JSON) {
return true;
}

log.warn("Unknown resource encoding: {}", encoding);
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import java.util.Collection;
import lombok.NonNull;
import lombok.SneakyThrows;
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
import org.hl7.fhir.common.hapi.validation.support.SnapshotGeneratingValidationSupport;
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
Expand Down Expand Up @@ -66,7 +65,10 @@ private FhirValidator createHapiFhirValidator(
ValidationModuleConfiguration configuration, ValidationSupportChain validationSupportChain) {
FhirInstanceValidator hapiValidatorModule = new FhirInstanceValidator(validationSupportChain);
hapiValidatorModule.setErrorForUnknownProfiles(configuration.isErrorOnUnknownProfile());
hapiValidatorModule.setNoExtensibleWarnings(true);
hapiValidatorModule.setNoExtensibleWarnings(
Boolean.parseBoolean(System.getenv().getOrDefault("DISABLE_EXTENSIBLE_WARNINGS", "true")));
hapiValidatorModule.setNoTerminologyChecks(
Boolean.parseBoolean(System.getenv().getOrDefault("DISABLE_TERMINOLOGY_CHECKS", "false")));
hapiValidatorModule.setAnyExtensionsAllowed(configuration.isAnyExtensionsAllowed());
FhirValidator fhirValidator = fhirContext.newValidator();
fhirValidator.registerValidatorModule(hapiValidatorModule);
Expand All @@ -91,12 +93,9 @@ private ValidationSupportChain createValidationSupportChain(
return new ValidationSupportChain(
new UcumValidationSupport(fhirContext, configuration.getUcumValidationSeverityLevel()),
new SnapshotGeneratingValidationSupport(fhirContext),
new CachingValidationSupport(
new IgnoreCodeSystemValidationSupport(
fhirContext, configuration.getIgnoredCodeSystems())),
new CachingValidationSupport(
new IgnoreValueSetValidationSupport(fhirContext, configuration.getIgnoredValueSets())),
new CachingValidationSupport(validationSupport),
new IgnoreCodeSystemValidationSupport(fhirContext, configuration.getIgnoredCodeSystems()),
new IgnoreValueSetValidationSupport(fhirContext, configuration.getIgnoredValueSets()),
validationSupport,
new PipedCanonicalCoreResourcesValidationSupport(fhirContext));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ public List<String> getAllReferencedProfilesInResource(String resourceBody) {
} catch (IOException e) {
throw new IllegalArgumentException("Could not parse resource", e);
}
} else allProfilesInResource = locateInXml(resourceBody);
} else {
allProfilesInResource = locateInXml(resourceBody);
}

return allProfilesInResource;
}
Expand All @@ -80,7 +82,9 @@ private List<String> locateInXml(String resource) throws IllegalArgumentExceptio
while (xmlEventReader.hasNext()) {
XMLEvent event = xmlEventReader.nextEvent();

if (event instanceof DTD) throw new SecurityException("DTD is not allowed");
if (event instanceof DTD) {
throw new SecurityException("DTD is not allowed");
}

if (event.isStartElement()) {
treeLevel++;
Expand Down Expand Up @@ -151,7 +155,9 @@ private void parseXmlEventsForProfiles(XMLEventReader xmlEventReader, List<Strin
while (xmlEventReader.hasNext()) {
event = xmlEventReader.nextEvent();
if (event.isEndElement()
&& event.asEndElement().getName().getLocalPart().equalsIgnoreCase("meta")) break;
&& event.asEndElement().getName().getLocalPart().equalsIgnoreCase("meta")) {
break;
}
if (event.isStartElement()) {
nextTag = event.asStartElement();
if (nextTag.getName().getLocalPart().equalsIgnoreCase(PROFILE_STRING)
Expand All @@ -171,9 +177,11 @@ private List<String> locateInJson(String resource) throws IOException {
int treeLevel = 0;
var token = jsonParser.nextToken();
while (jsonParser.hasCurrentToken()) {
if (token.isStructStart()) treeLevel++;
else if (token.isStructEnd()) treeLevel--;
else {
if (token.isStructStart()) {
treeLevel++;
} else if (token.isStructEnd()) {
treeLevel--;
} else {
if (treeLevel <= 2) {
String fieldName = jsonParser.currentName();
if ("meta".equals(fieldName)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
class ValidationResultOutputFilter {
public ValidationResult apply(
ValidationResult result, ValidationMessagesFilter validationMessagesFilter) {
if (validationMessagesFilter == ValidationMessagesFilter.KEEP_ALL) return result;
if (validationMessagesFilter == ValidationMessagesFilter.KEEP_ALL) {
return result;
}

if (validationMessagesFilter == ValidationMessagesFilter.KEEP_ERRORS_AND_WARNINGS_ONLY) {
var filteredMessages =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,19 @@ public PipedCanonicalCoreResourcesValidationSupport(FhirContext ctx) {
@Override
public IBaseResource fetchStructureDefinition(String theUrl) {
Profile p = Profile.parse(theUrl);
if (p.getVersion() == null) return null;
if (p.getVersion() == null) {
return null;
}

IValidationSupport support = ctx.getValidationSupport();
IBaseResource resource = support.fetchStructureDefinition(p.getBaseCanonical());
if (resource == null) return null;
if (resource == null) {
return null;
}

if (Strings.CS.equals(((StructureDefinition) resource).getVersion(), p.getVersion()))
if (Strings.CS.equals(((StructureDefinition) resource).getVersion(), p.getVersion())) {
return resource;
}

return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,14 @@
@Slf4j
public class UcumValidationSupport implements IValidationSupport {

private FhirContext fhirContext;
private final FhirContext fhirContext;

private IssueSeverity issueSeverity;
private final IssueSeverity issueSeverity;

public UcumValidationSupport(FhirContext theFhirContext, IssueSeverity issueSeverity) {
this.fhirContext = theFhirContext;
this.issueSeverity = issueSeverity;
this.issueSeverity = issueSeverity != null ? issueSeverity : IssueSeverity.ERROR;
;
}

@Override
Expand Down Expand Up @@ -113,8 +114,9 @@ public CodeValidationResult validateCode(
String theValueSetUrl) {
LookupCodeResult lookupResult =
lookupCode(theValidationSupportContext, theCodeSystem, theCode, null);
if (lookupResult.isFound())
if (lookupResult != null && lookupResult.isFound()) {
return new CodeValidationResult().setCode(theCode).setDisplay(lookupResult.getCodeDisplay());
}

// The presence of only the following two attributes is important to make sure the code
// validation will result in a Warning or an Error
Expand Down
18 changes: 18 additions & 0 deletions commons/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration>

<configuration>
<import class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"/>
<import class="ch.qos.logback.core.ConsoleAppender"/>

<appender name="Console" class="ConsoleAppender">
<encoder class="PatternLayoutEncoder">
<pattern>[%d{ISO8601}] [%p] [%t] [%c] %m%n</pattern>
</encoder>
</appender>

<variable name="ROOT_LOG_LEVEL" value="${ROOT_LOG_LEVEL:-INFO}"/>
<root level="${ROOT_LOG_LEVEL}">
<appender-ref ref="Console"/>
</root>
</configuration>
Loading
Loading