Skip to content

Commit

Permalink
stand-alone validator working, workaround for icd10-gm, ops, pzn
Browse files Browse the repository at this point in the history
Added a "code ok" validation support impl that assumes that codes from
http://fhir.de/CodeSystem/bfarm/icd-10-gm,
http://fhir.de/CodeSystem/dimdi/icd-10-gm,
http://fhir.de/CodeSystem/bfarm/ops,
http://fhir.de/CodeSystem/dimdi/ops, http://fhir.de/CodeSystem/ifa/pzn
are always valid, this workaround is fine if the codes are later checked
against an expanded ValueSet.

Fixed copy-dependencies build step for stand-alone validator
  • Loading branch information
hhund committed Oct 11, 2023
1 parent 576ef36 commit be9b555
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 27 deletions.
8 changes: 4 additions & 4 deletions codex-process-data-transfer/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -178,10 +178,10 @@
hapi-fhir-base,hapi-fhir-client,hapi-fhir-converter,hapi-fhir-structures-r4,hapi-fhir-structures-r5,hapi-fhir-validation,hapi-fhir-validation-resources-r4,
hapi-fhir-validation-resources-r5,org.hl7.fhir.convertors,org.hl7.fhir.dstu2,org.hl7.fhir.dstu2016may,org.hl7.fhir.dstu3,org.hl7.fhir.r4,org.hl7.fhir.r5,org.hl7.fhir.utilities,
org.hl7.fhir.validation,jackson-annotations,jackson-core,jackson-databind,jackson-module-jaxb-annotations,caffeine,guava,
commons-codec,commons-io,crypto-utils,log4j2-utils,jakarta.activation,jakarta.annotation-api,jakarta.ws.rs-api,jakarta.xml.bind-api,commons-compress,commons-lang3,commons-text,
httpclient,httpcore,log4j-api,log4j-core,log4j-slf4j-impl,bcpkix-jdk15on,bcprov-jdk15on,bcutil-jdk15on,ucum,hk2-api,hk2-locator,hk2-utils,osgi-resource-locator,
aopalliance-repackaged,jakarta.inject,jersey-apache-connector,jersey-client,jersey-common,jersey-entity-filtering,jersey-hk2,jersey-media-jaxb,jersey-media-json-jackson,
dsf-bpe-process-base,dsf-fhir-rest-adapter,dsf-fhir-validation,dsf-openehr-model,jcl-over-slf4j,
commons-codec,commons-io,crypto-utils,jakarta.activation,jakarta.annotation-api,jakarta.ws.rs-api,jakarta.xml.bind-api,commons-compress,commons-lang3,commons-text,
httpclient,httpcore,log4j-api,log4j-core,log4j-slf4j2-impl,bcpkix-jdk18on,bcprov-jdk18on,bcutil-jdk18on,ucum,hk2-api,hk2-locator,hk2-utils,osgi-resource-locator,
aopalliance-repackaged,jakarta.inject-api,jersey-apache-connector,jersey-client,jersey-common,jersey-entity-filtering,jersey-hk2,jersey-media-jaxb,jersey-media-json-jackson,
dsf-bpe-process-api-v1,dsf-fhir-auth,dsf-fhir-rest-adapter,dsf-fhir-validation,dsf-openehr-model,jcl-over-slf4j,
slf4j-api,spring-aop,spring-beans,spring-context,spring-core,spring-expression,spring-jcl,thymeleaf,unbescape,xpp3,xpp3_xpath
</includeArtifactIds>
</configuration>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.fasterxml.jackson.databind.ObjectMapper;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.IValidationSupport;
import de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation.BundleValidatorFactory;
Expand All @@ -52,7 +54,6 @@
import de.rwh.utils.crypto.CertificateHelper;
import de.rwh.utils.crypto.io.CertificateReader;
import de.rwh.utils.crypto.io.PemIo;
import dev.dsf.bpe.v1.ProcessPluginApi;
import dev.dsf.bpe.v1.documentation.ProcessDocumentation;
import dev.dsf.fhir.validation.SnapshotGenerator;
import dev.dsf.fhir.validation.ValueSetExpander;
Expand Down Expand Up @@ -218,8 +219,13 @@ public static enum TerminologyServerConnectionTestStatus
@Value("${java.io.tmpdir}")
private String systemTempFolder;

// not using process plugin api to enable reuse of this config class in stand-alone validator
@Autowired
private FhirContext fhirContext;

// not using process plugin api to enable reuse of this config class in stand-alone validator
@Autowired
private ProcessPluginApi api;
private ObjectMapper objectMapper;


@Bean
Expand All @@ -230,9 +236,9 @@ public ValidationPackageManager validationPackageManager()
EnumSet<BindingStrength> bindingStrengths = EnumSet.copyOf(
valueSetExpansionBindingStrengths.stream().map(BindingStrength::fromCode).collect(Collectors.toList()));

return new ValidationPackageManagerImpl(validationPackageClient(), valueSetExpansionClient(),
api.getObjectMapper(), api.getFhirContext(), internalSnapshotGeneratorFactory(),
internalValueSetExpanderFactory(), noDownload, bindingStrengths);
return new ValidationPackageManagerImpl(validationPackageClient(), valueSetExpansionClient(), objectMapper,
fhirContext, internalSnapshotGeneratorFactory(), internalValueSetExpanderFactory(), noDownload,
bindingStrengths);
}

private StructureDefinitionModifier createStructureDefinitionModifier(String className)
Expand Down Expand Up @@ -368,7 +374,7 @@ else if (clientCertificateFile == null && clientCertificatePrivateKeyFile == nul
@Bean
public ValidationPackageClient validationPackageClient()
{
return new ValidationPackageClientWithFileSystemCache(packageCacheFolder(), api.getObjectMapper(),
return new ValidationPackageClientWithFileSystemCache(packageCacheFolder(), objectMapper,
validationPackageClientJersey());
}

Expand Down Expand Up @@ -410,7 +416,7 @@ public ValueSetExpansionClient valueSetExpansionClient()
List<ValueSetModifier> modifiers = valueSetModifierClasses.stream().map(this::createValueSetModifier)
.collect(Collectors.toList());

return new ValueSetExpansionClientWithFileSystemCache(valueSetCacheFolder(), api.getFhirContext(),
return new ValueSetExpansionClientWithFileSystemCache(valueSetCacheFolder(), fhirContext,
new ValueSetExpansionClientWithModifiers(valueSetExpansionClientJersey(), modifiers));
}

Expand Down Expand Up @@ -464,8 +470,7 @@ private ValueSetExpansionClient valueSetExpansionClientJersey()
valueSetExpansionClientBasicAuthUsername, valueSetExpansionClientBasicAuthPassword,
valueSetExpansionClientProxySchemeHostPort, valueSetExpansionClientProxyUsername,
valueSetExpansionClientProxyPassword, valueSetExpansionClientConnectTimeout,
valueSetExpansionClientReadTimeout, valueSetExpansionClientVerbose, api.getObjectMapper(),
api.getFhirContext());
valueSetExpansionClientReadTimeout, valueSetExpansionClientVerbose, objectMapper, fhirContext);
}

public TerminologyServerConnectionTestStatus testConnectionToTerminologyServer()
Expand Down Expand Up @@ -524,7 +529,8 @@ public BundleValidatorFactory bundleValidatorFactory()
validationPackageIdentifiers());
}

private List<ValidationPackageIdentifier> validationPackageIdentifiers()
@Bean
public List<ValidationPackageIdentifier> validationPackageIdentifiers()
{
if (validationPackages == null || validationPackages.isEmpty())
throw new IllegalArgumentException("Validation packages not specified");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package de.netzwerk_universitaetsmedizin.codex.processes.data_transfer.validation;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.support.ConceptValidationOptions;
import ca.uhn.fhir.context.support.IValidationSupport;
import ca.uhn.fhir.context.support.ValidationSupportContext;

public class NonValidatingValidationSupport implements IValidationSupport
{
private static final Logger logger = LoggerFactory.getLogger(NonValidatingValidationSupport.class);

private final FhirContext fhirContext;
private final List<String> notValidatedCodeSystemSystems = new ArrayList<>();

public NonValidatingValidationSupport(FhirContext fhirContext, String... notValidatedCodeSystemSystems)
{
this(fhirContext, Arrays.asList(notValidatedCodeSystemSystems));
}

public NonValidatingValidationSupport(FhirContext fhirContext, Collection<String> notValidatedCodeSystemSystems)
{
this.fhirContext = fhirContext;

if (notValidatedCodeSystemSystems != null)
this.notValidatedCodeSystemSystems.addAll(notValidatedCodeSystemSystems);
}

@Override
public FhirContext getFhirContext()
{
return fhirContext;
}

@Override
public CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext,
ConceptValidationOptions theOptions, String system, String code, String display, String valueSetUrl)
{
if (notValidatedCodeSystemSystems.contains(system))
{
logger.warn("Not validating code {} from system {} for valueSet {}", code, system, valueSetUrl);
return new CodeValidationResult().setCode(code).setCodeSystemName(system).setDisplay(display);
}

else
return null;
}

@Override
public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String system)
{
return notValidatedCodeSystemSystems.contains(system);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.stream.Stream;
Expand All @@ -23,6 +25,11 @@
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.EnumerablePropertySource;

import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;

import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.i18n.HapiLocalizer;
import ca.uhn.fhir.parser.IParser;
Expand Down Expand Up @@ -70,7 +77,7 @@ public static class TestConfig
private ValidationPackageManager packageManager;

@Autowired
private ValidationPackageIdentifier validationPackage;
private List<ValidationPackageIdentifier> validationPackageIdentifiers;

@Autowired
private ValueSetExpansionClient valueSetExpansionClient;
Expand All @@ -79,7 +86,15 @@ public static class TestConfig
private ConfigurableEnvironment environment;

@Bean
public FhirContext fhirContext()
public ObjectMapper getObjectMapper()
{
return JsonMapper.builder().serializationInclusion(Include.NON_NULL)
.serializationInclusion(Include.NON_EMPTY).disable(MapperFeature.AUTO_DETECT_CREATORS)
.disable(MapperFeature.AUTO_DETECT_FIELDS).disable(MapperFeature.AUTO_DETECT_SETTERS).build();
}

@Bean
public FhirContext getFhirContext()
{
FhirContext context = FhirContext.forR4();
HapiLocalizer localizer = new HapiLocalizer()
Expand All @@ -97,14 +112,15 @@ public Locale getLocale()
@Bean
public ValidationMain validatorMain()
{
return new ValidationMain(environment, fhirContext(), packageManager, validationPackage, output,
outputPretty, valueSetExpansionClient);
return new ValidationMain(environment, getFhirContext(), packageManager, validationPackageIdentifiers,
output, outputPretty, valueSetExpansionClient);
}
}

public static enum Output
{
JSON, XML

}

public static void main(String[] args)
Expand Down Expand Up @@ -137,19 +153,20 @@ public static void main(String[] args)
private final ConfigurableEnvironment environment;
private final FhirContext fhirContext;
private final ValidationPackageManager packageManager;
private final ValidationPackageIdentifier validationPackage;
private final List<ValidationPackageIdentifier> validationPackageIdentifiers = new ArrayList<>();
private final Output output;
private final boolean outputPretty;
private final ValueSetExpansionClient valueSetExpansionClient;

public ValidationMain(ConfigurableEnvironment environment, FhirContext fhirContext,
ValidationPackageManager packageManager, ValidationPackageIdentifier validationPackage, Output output,
boolean outputPretty, ValueSetExpansionClient valueSetExpansionClient)
ValidationPackageManager packageManager, List<ValidationPackageIdentifier> validationPackageIdentifiers,
Output output, boolean outputPretty, ValueSetExpansionClient valueSetExpansionClient)
{
this.environment = environment;
this.fhirContext = fhirContext;
this.packageManager = packageManager;
this.validationPackage = validationPackage;
if (validationPackageIdentifiers != null)
this.validationPackageIdentifiers.addAll(validationPackageIdentifiers);
this.output = output;
this.outputPretty = outputPretty;
this.valueSetExpansionClient = valueSetExpansionClient;
Expand All @@ -161,18 +178,16 @@ public void afterPropertiesSet() throws Exception
Objects.requireNonNull(environment, "environment");
Objects.requireNonNull(fhirContext, "fhirContext");
Objects.requireNonNull(packageManager, "packageManager");
Objects.requireNonNull(validationPackage, "validationPackage");
Objects.requireNonNull(output, "output");
Objects.requireNonNull(valueSetExpansionClient, "valueSetExpansionClient");
}

public void validate(String[] files)
{
logger.info("Using validation package {}", validationPackage);
logger.info("Using validation packages {}", validationPackageIdentifiers);
getAllNumProperties().forEach(c -> logger.debug("Config: {}", c));

BundleValidator validator = packageManager.createBundleValidator(validationPackage.getName(),
validationPackage.getVersion());
BundleValidator validator = packageManager.createBundleValidator(validationPackageIdentifiers);

Arrays.stream(files).map(this::read).filter(r -> r != null).forEach(r ->
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,4 +148,16 @@ default BundleValidator createBundleValidator(String name, String version)
* @return {@link BundleValidator} for the specified FHIR package
*/
BundleValidator createBundleValidator(ValidationPackageIdentifier identifier);

/**
* Downloads the given FHIR packages and all its dependencies. Will try to generate snapshots for all
* {@link StructureDefinition}s of the specified (root) package and its dependencies, will try to expand all
* {@link ValueSet}s with binding strength {@link BindingStrength#EXTENSIBLE}, {@link BindingStrength#PREFERRED} or
* {@link BindingStrength#REQUIRED} used by the {@link StructureDefinition} of the specified (root) package or their
* dependencies, before returning a {@link IValidationSupport}.
*
* @param identifiers
* @return {@link BundleValidator} for the specified FHIR packages
*/
BundleValidator createBundleValidator(List<ValidationPackageIdentifier> identifiers);
}
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,17 @@ public BundleValidator createBundleValidator(IValidationSupport validationSuppor
return validator;
}

@Override
public BundleValidator createBundleValidator(List<ValidationPackageIdentifier> identifiers)
{
Objects.requireNonNull(identifiers, "identifiers");

List<ValidationPackageWithDepedencies> packageWithDependencies = downloadPackagesWithDependencies(identifiers);
IValidationSupport validationSupport = expandValueSetsAndGenerateStructureDefinitionSnapshots(
packageWithDependencies);
return createBundleValidator(validationSupport, packageWithDependencies);
}

@Override
public BundleValidator createBundleValidator(ValidationPackageIdentifier identifier)
{
Expand Down Expand Up @@ -409,7 +420,11 @@ private ValidationSupportChain createSupportChain(FhirContext context,
getAll(ValidationPackageWithDepedencies::getAllStructureDefinitions, packagesWithDependencies),
getAll(ValidationPackageWithDepedencies::getAllCodeSystems, packagesWithDependencies),
getAll(ValidationPackageWithDepedencies::getAllValueSets, packagesWithDependencies)),
new DefaultProfileValidationSupport(context), new QuietCommonCodeSystemsTerminologyService(context));
new DefaultProfileValidationSupport(context), new QuietCommonCodeSystemsTerminologyService(context),
// TODO remove NonValidatingValidationSupport
new NonValidatingValidationSupport(context, "http://fhir.de/CodeSystem/bfarm/icd-10-gm",
"http://fhir.de/CodeSystem/dimdi/icd-10-gm", "http://fhir.de/CodeSystem/bfarm/ops",
"http://fhir.de/CodeSystem/dimdi/ops", "http://fhir.de/CodeSystem/ifa/pzn"));
}

private <V> List<V> getAll(Function<ValidationPackageWithDepedencies, List<V>> mapper,
Expand Down

0 comments on commit be9b555

Please sign in to comment.