Skip to content

Commit

Permalink
Release 0.6.0
Browse files Browse the repository at this point in the history
  • Loading branch information
Gematik-Entwicklung committed May 24, 2023
1 parent d7129e4 commit 8728fbb
Show file tree
Hide file tree
Showing 135 changed files with 16,468 additions and 85 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,12 @@ Abweichend vom allgemeinen Prüfumfang verhält sich das ISIK1-Modul wie folgt:
- Codes aus den CodeSystemen `http://snomed.info/sct`, `http://fhir.de/CodeSystem/bfarm/icd-10-gm` und `http://fhir.de/CodeSystem/bfarm/ops` werden nicht validiert
- Folgende ValueSets werden nicht validiert: `https://gematik.de/fhir/isik/v2/Basismodul/ValueSet/ProzedurenCodesSCT`, `https://gematik.de/fhir/isik/v2/Basismodul/ValueSet/DiagnosesSCT`, `https://gematik.de/fhir/isik/v2/Basismodul/ValueSet/ProzedurenKategorieSCT` und `http://fhir.de/ValueSet/bfarm/ops`

### DIGA-Modul

Abweichend vom allgemeinen Prüfumfang verhält sich das DIGA-Modul wie folgt:
- Codes aus den CodeSystemen `http://fhir.de/CodeSystem/ifa/pzn` und `http://fhir.de/CodeSystem/dimdi/atc` werden nicht validiert


Die eingebundenen Packages, unterstützte Profile und Versionen findet man [hier](supported-profiles.md).

## Erste Schritte
Expand Down Expand Up @@ -131,6 +137,12 @@ Unterstützte Modulnamen:
- `isip1` (Informationstechnische Systeme in der Pflege Stufe 1)
- `isik2` (Informationstechnische Systeme in Krankenhäusern Stufe 2)
- `isik1` (Informationstechnische Systeme in Krankenhäusern Stufe 1)
- `diga` (Digitale Gesundheitsanwendungen)

Weitere Parameter:
- `-e` - Nur Validierungsmeldungen der Stufen ERROR und FATAL ausgeben (keine INFO und WARN-Meldungen)
- `-v` - Verbode-Modus mit Debug-Ausgaben


### Java-Bibliothek

Expand Down
10 changes: 10 additions & 0 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

# Release Notes Gematik Referenzvalidator

## Release 0.6.0

### added
- New validation module: diga (Digitale Gesundheitsanwendungen)
- New command line arguments for filtering the output of the validation process

### changed
- removed packages de.gematik.erezept-patientenrechnung.r4-1.0.0.tgz, kbv.ita.erp-1.1.0.tgz and de.gematik.erezept-workflow.r4-1.2.0.tgz
- added packages de.gematik.erezept-patientenrechnung.r4-1.0.1.tgz, kbv.ita.erp-1.1.1.tgz and de.gematik.erezept-workflow.r4-1.2.1.tgz

## Release 0.5.0

### added
Expand Down
2 changes: 1 addition & 1 deletion 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>0.5.0</version>
<version>0.6.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down
122 changes: 120 additions & 2 deletions cli/src/main/java/de/gematik/refv/cli/ReferenceValidator.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,22 @@

package de.gematik.refv.cli;

import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhir.validation.SingleValidationMessage;
import de.gematik.refv.SupportedValidationModule;
import de.gematik.refv.ValidationModuleFactory;
import de.gematik.refv.commons.validation.ValidationModule;
import de.gematik.refv.commons.validation.ValidationResult;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import org.apache.log4j.Category;
import org.apache.log4j.LogManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import picocli.CommandLine;

import java.nio.file.Path;
import java.util.Enumeration;
import java.util.Optional;

@CommandLine.Command(
Expand All @@ -43,17 +48,27 @@ public class ReferenceValidator implements Runnable {
@CommandLine.Option(names = {"-i", "--input"}, required = true)
private Path filePath;

@CommandLine.Option(names = {"-e", "--errors-only"}, required = false)
private boolean isOnlyErrorsInOutput;

@CommandLine.Option(names = {"-v", "--verbose"}, required = false)
private boolean isVerbose;

static Logger logger = LoggerFactory.getLogger(ReferenceValidator.class);

private ValidationModuleFactory factory;

public static void main(String[] args) {
var cli = new CommandLine(new ReferenceValidator(null, null, new ValidationModuleFactory())).setCaseInsensitiveEnumValuesAllowed(true);
var cli = new CommandLine(new ReferenceValidator(null, null, false, false, new ValidationModuleFactory())).setCaseInsensitiveEnumValuesAllowed(true);
cli.execute(args);
}

public void run() {
try {
if(isVerbose) {
configureAllLoggersToDebug();
}

Optional<SupportedValidationModule> supportedValidationModule = SupportedValidationModule.fromString(module);
if(supportedValidationModule.isEmpty()) {
logger.error("Module [{}] unsupported. Supported modules: {}", module, SupportedValidationModule.values());
Expand All @@ -62,9 +77,112 @@ public void run() {

ValidationModule validator = factory.createValidationModule(supportedValidationModule.get());
ValidationResult result = validator.validateFile(filePath);
logger.info("Validation result: {}", result);

String outputMessage = buildOutputMessage(result);
logger.info("\r\n{}", outputMessage);
} catch (Exception e){
logger.error("Exception", e);
}
}

private static void configureAllLoggersToDebug() {
org.apache.log4j.Logger logger4j = org.apache.log4j.Logger.getRootLogger();
logger4j.setLevel(org.apache.log4j.Level.toLevel("DEBUG"));
Enumeration<Category> loggers = LogManager.getCurrentLoggers();
while (loggers.hasMoreElements()) {
Category logger = loggers.nextElement();
logger4j = org.apache.log4j.Logger.getLogger(logger.getName());
logger4j.setLevel(org.apache.log4j.Level.toLevel("DEBUG"));
}
}

protected String buildOutputMessage(ValidationResult results)
{
StringBuilder sb = new StringBuilder("\n");

sb.append( "===== Valid: " );
if( results.isValid() )
sb.append( "true =====\n\n" );
else
sb.append( "false =====\n\n" );

if(isDetailsShouldBePrinted(results)
) {
if(isOnlyErrorsInOutput){
sb.append("See ")
.append((getCountFor(ResultSeverityEnum.ERROR, results) + getCountFor(ResultSeverityEnum.FATAL, results)))
.append(" errors below.\n\n");
} else {
sb.append("See ")
.append(getCountFor(ResultSeverityEnum.ERROR, results) + getCountFor(ResultSeverityEnum.FATAL, results))
.append(" errors, ")
.append(getCountFor(ResultSeverityEnum.WARNING, results))
.append(" warnings and ")
.append(getCountFor(ResultSeverityEnum.INFORMATION, results))
.append(" other notes below.\n\n");
}

sb.append(" ")
.append(padRight(" ", 4))
.append(padRight("Severity", 13))
.append(padRight("Code", 45))
.append("Location (FHIRPath) ")
.append("Profile, Element and Problem description\n")
.append(" ")
.append(padRight(" ", 4))
.append(padRight("-------- ", 13))
.append(padRight("----------------------------------------", 45))
.append("------------------- ")
.append("----------------------------------------\n");

int count = 1;

for (SingleValidationMessage message : results.getValidationMessages()) {
if (isOnlyErrorsInOutput && !isErrorMessage(message)) {
continue;
}
sb.append(" ")
.append(padRight("" + count++, 4))
.append(padRight(message.getSeverity().toString(), 13))
.append(padRight(message.getMessageId(), 45))
.append(message.getLocationString()).append(" ")
.append(message.getMessage()).append('\n');
}
}


return sb.toString();
}

private int getCountFor(ResultSeverityEnum severity, ValidationResult results) {
int count = 0;
for(SingleValidationMessage message : results.getValidationMessages()){
if(message.getSeverity() == severity)
count++;
}
return count;
}

private boolean isDetailsShouldBePrinted(ValidationResult results) {
if(results.getValidationMessages().isEmpty())
return false;

if(isAtLeastOneErrorInMessages(results))
return true;

return !isOnlyErrorsInOutput;
}

private static boolean isAtLeastOneErrorInMessages(ValidationResult results) {
return results.getValidationMessages().stream().anyMatch(ReferenceValidator::isErrorMessage);
}

private static boolean isErrorMessage(SingleValidationMessage m) {
return m.getSeverity() == ResultSeverityEnum.ERROR || m.getSeverity() == ResultSeverityEnum.FATAL;
}

public static String padRight(String s, int n) {
String format = "%-" + n + "s";
return String.format(format, s);
}
}
3 changes: 2 additions & 1 deletion cli/src/main/resources/log4j.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Set root logger level to DEBUG and its only appender to A1.
log4j.rootLogger=INFO, A1
log4j.rootLogger=WARN, A1
log4j.logger.de.gematik.refv = INFO

# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
Expand Down
71 changes: 67 additions & 4 deletions cli/src/test/java/de/gematik/refv/cli/ReferenceValidatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,23 @@

package de.gematik.refv.cli;


import de.gematik.refv.SupportedValidationModule;
import de.gematik.refv.ValidationModuleFactory;
import de.gematik.refv.cli.support.TestAppender;
import de.gematik.refv.valmodule.base.ConfigurationBasedValidationModule;
import lombok.SneakyThrows;
import org.apache.log4j.Level;
import org.apache.log4j.spi.LoggingEvent;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import org.apache.log4j.Logger;

import java.nio.file.Path;
import java.nio.file.Paths;
Expand All @@ -39,7 +46,6 @@ class ReferenceValidatorTest {
@Mock
ConfigurationBasedValidationModule module;


@SneakyThrows
@Test
void testValidationModuleIsCalled() {
Expand All @@ -48,7 +54,7 @@ void testValidationModuleIsCalled() {
Path inputFile = Paths.get("src/non-existingfile.xml");
String moduleCode = SupportedValidationModule.ERP.toString();

new ReferenceValidator(moduleCode, inputFile, factory).run();
new ReferenceValidator(moduleCode, inputFile, false, false, factory).run();

Mockito.verify(module).validateFile(inputFile);
}
Expand All @@ -58,8 +64,65 @@ void testValidationModuleIsCalled() {
void testUnknownModuleInterruptsExecution() {
Path inputFile = Paths.get("src/non-existingfile.xml");

new ReferenceValidator("unknown-module", inputFile, factory).run();
new ReferenceValidator("unknown-module", inputFile, false, false, factory).run();

Mockito.verifyNoInteractions(factory);
}

@SneakyThrows
@ParameterizedTest
@ValueSource( strings = {
"-m erp -i src/test/resources/erp-test.xml",
"-m eau -i src/test/resources/eau-test.xml",
"-m isik1 -i src/test/resources/isik1-test.json",
"-m isik2 -i src/test/resources/isik2-test.json",
"-m isip1 -i src/test/resources/isip1-test.json",
"-m diga -i src/test/resources/diga-test.xml"
})
void testValidCliInput(String input){
TestAppender appender = getTestAppender();

String [] args = input.split(" ");
ReferenceValidator.main(args);

boolean isValid = false;
for (LoggingEvent event : appender.getLogs()) {
if(event.getMessage().toString().contains("Valid: true"))
isValid = true;
}
Assertions.assertTrue(isValid);
}

private static TestAppender getTestAppender() {
Logger logger = Logger.getRootLogger();
TestAppender appender = new TestAppender();
logger.addAppender(appender);
return appender;
}

@Test
void testVerboseMode() {
TestAppender appender = getTestAppender();

String input = "-m isik1 -i src/test/resources/isik1-test.json -v";
String [] args = input.split(" ");
ReferenceValidator.main(args);


boolean isValid = appender.getLogs().stream().anyMatch(e -> e.getLevel().equals(Level.DEBUG));
Assertions.assertTrue(isValid,"No debug messages in verbose mode found");
}

@Test
void testOnlyErrorsInOutput() {
TestAppender appender = getTestAppender();

String input = "-m isik1 -i src/test/resources/isik1-test-errors.json -e";
String [] args = input.split(" ");
ReferenceValidator.main(args);


boolean isValid = appender.getLogs().stream().noneMatch(l -> l.getMessage().toString().contains("INFORMATION"));
Assertions.assertTrue(isValid,"Information message found in output - only errors are allowed");
}
}
29 changes: 29 additions & 0 deletions cli/src/test/java/de/gematik/refv/cli/support/TestAppender.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package de.gematik.refv.cli.support;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.spi.LoggingEvent;

import java.util.ArrayList;
import java.util.List;

public class TestAppender extends AppenderSkeleton {
private final List<LoggingEvent> log = new ArrayList<>();

@Override
public boolean requiresLayout() {
return false;
}

@Override
protected void append(final LoggingEvent loggingEvent) {
log.add(loggingEvent);
}

@Override
public void close() {
}

public List<LoggingEvent> getLogs() {
return new ArrayList<>(log);
}
}
Loading

0 comments on commit 8728fbb

Please sign in to comment.