Skip to content

Commit

Permalink
Add support for loading custom vocabulary configs in realtime
Browse files Browse the repository at this point in the history
-See code validator for implementation
-2 new properties added in referenceccdaservice.xml
--referenceccda.isDynamicVocab
---Set to false if wating to use a single pre-loaded default config only
like past versions of the validator
---Set to true for the option to use one or more custom dynamically
loaded configs determined by API form-data vocabularyConfig key which
should have a value set to the name of the file excepting the .xml
extension
--referenceccda.configFolder
---Set to the path to hold the configs. This can be the same directory
as the current default config path or a completely different directory.
Error handling is implemented to handle either scenario. If for any
reason a custom dynamic config is not found, the default config will be
loaded, if it exists.
  • Loading branch information
drbgfc committed Jun 13, 2018
1 parent bf96fe2 commit 852dc26
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 168 deletions.
5 changes: 5 additions & 0 deletions configuration/dynamic/ccdaScorecardConfig.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<configurations>

<!-- TODO: Define the differences for this -->

</configurations>
6 changes: 4 additions & 2 deletions configuration/referenceccdaservice.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Save a backup of this completed configuration file
<Context reloadable="true">
<Parameter name="vocabulary.localCodeRepositoryDir" value="path/to/your/code_repository" override="true"/>
<Parameter name="vocabulary.localValueSetRepositoryDir" value="path/to/your/valueset_repository" override="true"/>
<Parameter name="referenceccda.configFile" value="path/to/your/ccdaReferenceValidatorConfig.xml" override="true"/>
<Parameter name="content.scenariosDir" value="path/to/your/scenarion_directory" override="true"/>
<Parameter name="referenceccda.configFile" value="path/to/your/configs_folder/ccdaReferenceValidatorConfig.xml" override="true"/>
<Parameter name="referenceccda.isDynamicVocab" value="false" override="true"/>
<Parameter name="referenceccda.configFolder" value="path/to/your/configs_folder" override="true"/>
<Parameter name="content.scenariosDir" value="path/to/your/scenarios_directory" override="true"/>
</Context>
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<java.version>1.7</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<code.validator.version>1.0.13</code.validator.version>
<code.validator.version>1.0.14-SNAPSHOT</code.validator.version>
<content.validator.version>1.0.19</content.validator.version>
<!-- MDHT properties -->
<mdht.models.version>3.0.8.20180531</mdht.models.version>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,76 +1,79 @@
package org.sitenv.referenceccda.controllers;

import org.sitenv.referenceccda.dto.ValidationResultsDto;
import org.sitenv.referenceccda.services.ReferenceCCDAValidationService;
import org.sitenv.referenceccda.services.VocabularyService;
import org.sitenv.vocabularies.validation.entities.Code;
import org.sitenv.vocabularies.validation.entities.VsacValueSet;
import org.sitenv.vocabularies.validation.services.VocabularyValidationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

@RestController
public class ReferenceCCDAValidationController {
@Autowired
ReferenceCCDAValidationService referenceCcdaValidationService;
@Autowired
VocabularyService vocabularyService;
@Autowired
VocabularyValidationService validationManager;

private static final String GITHUB_URL = "https://api.github.com/repos/siteadmin/2015-Certification-C-CDA-Test-Data/git/trees/master?recursive=1";

@RequestMapping(value = "/", headers = "content-type=multipart/*", method = RequestMethod.POST)
public ValidationResultsDto doValidation(
@RequestParam(value = "validationObjective", required = true) String validationObjective,
@RequestParam(value = "referenceFileName", required = true) String referenceFileName,
@RequestParam(value = "ccdaFile", required = true) MultipartFile ccdaFile) {
return referenceCcdaValidationService.validateCCDA(validationObjective, referenceFileName, ccdaFile);
}

@RequestMapping(value = "/getvaluesetsbyoids", method = RequestMethod.GET)
public List<VsacValueSet> getValuesetsByOids(@RequestParam(value = "oids", required = true) String[] valuesetOids){
return vocabularyService.getValuesetsByOids(Arrays.asList(valuesetOids));
}

@RequestMapping(value = "/getbycodeincodesystem", method = RequestMethod.GET)
public List<Code> getByCodeInCodeSystems(@RequestParam(value = "code", required = true)String code, @RequestParam(value = "codeSystems", required = true) String[] codeSystems){
return vocabularyService.getByCodeInCodesystems(code, Arrays.asList(codeSystems));
}

@RequestMapping(value = "/getbycodeinvaluesetoid", method = RequestMethod.GET)
public List<VsacValueSet> getByCodeInValuesetOid(@RequestParam(value = "code", required = true)String code, @RequestParam(value = "oids", required = true) String[] valuesetOids){
return vocabularyService.getByCodeInValuesetOids(code, Arrays.asList(valuesetOids));
}

@RequestMapping(value = "/iscodeandisplaynameincodesystem", method = RequestMethod.GET)
public boolean isCodeAndDisplayNameFoundInCodeSystems(@RequestParam(value = "code", required = true)String code, @RequestParam(value = "displayName", required = true)String displayName, @RequestParam(value = "codeSystems", required = true) String[] codeSystems){
return vocabularyService.isCodeAndDisplayNameFoundInCodeSystems(code, displayName, Arrays.asList(codeSystems));
}

@RequestMapping(value = "/iscodeincodesystem", method = RequestMethod.GET)
public boolean isCodeFoundInCodeSystems(@RequestParam(value = "code", required = true)String code, @RequestParam(value = "codeSystems", required = true) String[] codeSystems){
return vocabularyService.isCodeFoundInCodesystems(code, Arrays.asList(codeSystems));
}

@RequestMapping(value = "/iscodeinvalueset", method = RequestMethod.GET)
public boolean isCodeFoundInValuesetOids(@RequestParam(value = "code", required = true)String code, @RequestParam(value = "valuesetOids", required = true) String[] valuesetOids){
return vocabularyService.isCodeFoundInValuesetOids(code, Arrays.asList(valuesetOids));
}

@Cacheable("messagetypeValidationObjectivesAndReferenceFilesMap")
@RequestMapping(value = "/senderreceivervalidationobjectivesandreferencefiles", method = RequestMethod.GET)
public Map<String, Map<String, List<String>>> getMapOfSenderAndRecieverValidationObjectivesWithReferenceFiles(){
return vocabularyService.getMapOfSenderAndRecieverValidationObjectivesWithReferenceFiles();
}

}
package org.sitenv.referenceccda.controllers;

import org.sitenv.referenceccda.dto.ValidationResultsDto;
import org.sitenv.referenceccda.services.ReferenceCCDAValidationService;
import org.sitenv.referenceccda.services.VocabularyService;
import org.sitenv.vocabularies.constants.VocabularyConstants;
import org.sitenv.vocabularies.validation.entities.Code;
import org.sitenv.vocabularies.validation.entities.VsacValueSet;
import org.sitenv.vocabularies.validation.services.VocabularyValidationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

@RestController
public class ReferenceCCDAValidationController {
@Autowired
ReferenceCCDAValidationService referenceCcdaValidationService;
@Autowired
VocabularyService vocabularyService;
@Autowired
VocabularyValidationService validationManager;

private static final String GITHUB_URL = "https://api.github.com/repos/siteadmin/2015-Certification-C-CDA-Test-Data/git/trees/master?recursive=1";

@RequestMapping(value = "/", headers = "content-type=multipart/*", method = RequestMethod.POST)
public ValidationResultsDto doValidation(
@RequestParam(value = "validationObjective", required = true) String validationObjective,
@RequestParam(value = "referenceFileName", required = true) String referenceFileName,
@RequestParam(value = "ccdaFile", required = true) MultipartFile ccdaFile,
@RequestParam(defaultValue = VocabularyConstants.Config.DEFAULT, required = false) String vocabularyConfig) {
return referenceCcdaValidationService.validateCCDA(validationObjective, referenceFileName, ccdaFile,
vocabularyConfig);
}

@RequestMapping(value = "/getvaluesetsbyoids", method = RequestMethod.GET)
public List<VsacValueSet> getValuesetsByOids(@RequestParam(value = "oids", required = true) String[] valuesetOids){
return vocabularyService.getValuesetsByOids(Arrays.asList(valuesetOids));
}

@RequestMapping(value = "/getbycodeincodesystem", method = RequestMethod.GET)
public List<Code> getByCodeInCodeSystems(@RequestParam(value = "code", required = true)String code, @RequestParam(value = "codeSystems", required = true) String[] codeSystems){
return vocabularyService.getByCodeInCodesystems(code, Arrays.asList(codeSystems));
}

@RequestMapping(value = "/getbycodeinvaluesetoid", method = RequestMethod.GET)
public List<VsacValueSet> getByCodeInValuesetOid(@RequestParam(value = "code", required = true)String code, @RequestParam(value = "oids", required = true) String[] valuesetOids){
return vocabularyService.getByCodeInValuesetOids(code, Arrays.asList(valuesetOids));
}

@RequestMapping(value = "/iscodeandisplaynameincodesystem", method = RequestMethod.GET)
public boolean isCodeAndDisplayNameFoundInCodeSystems(@RequestParam(value = "code", required = true)String code, @RequestParam(value = "displayName", required = true)String displayName, @RequestParam(value = "codeSystems", required = true) String[] codeSystems){
return vocabularyService.isCodeAndDisplayNameFoundInCodeSystems(code, displayName, Arrays.asList(codeSystems));
}

@RequestMapping(value = "/iscodeincodesystem", method = RequestMethod.GET)
public boolean isCodeFoundInCodeSystems(@RequestParam(value = "code", required = true)String code, @RequestParam(value = "codeSystems", required = true) String[] codeSystems){
return vocabularyService.isCodeFoundInCodesystems(code, Arrays.asList(codeSystems));
}

@RequestMapping(value = "/iscodeinvalueset", method = RequestMethod.GET)
public boolean isCodeFoundInValuesetOids(@RequestParam(value = "code", required = true)String code, @RequestParam(value = "valuesetOids", required = true) String[] valuesetOids){
return vocabularyService.isCodeFoundInValuesetOids(code, Arrays.asList(valuesetOids));
}

@Cacheable("messagetypeValidationObjectivesAndReferenceFilesMap")
@RequestMapping(value = "/senderreceivervalidationobjectivesandreferencefiles", method = RequestMethod.GET)
public Map<String, Map<String, List<String>>> getMapOfSenderAndRecieverValidationObjectivesWithReferenceFiles(){
return vocabularyService.getMapOfSenderAndRecieverValidationObjectivesWithReferenceFiles();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.sitenv.referenceccda.validators.schema.ReferenceCCDAValidator;
import org.sitenv.referenceccda.validators.schema.ValidationObjectives;
import org.sitenv.referenceccda.validators.vocabulary.VocabularyCCDAValidator;
import org.sitenv.vocabularies.constants.VocabularyConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
Expand Down Expand Up @@ -50,11 +51,21 @@ public ReferenceCCDAValidationService(ReferenceCCDAValidator referenceCCDAValida
}

public ValidationResultsDto validateCCDA(String validationObjective, String referenceFileName, MultipartFile ccdaFile) {
return validateCCDAImplementation(validationObjective, referenceFileName, ccdaFile, VocabularyConstants.Config.DEFAULT);
}

public ValidationResultsDto validateCCDA(String validationObjective, String referenceFileName, MultipartFile ccdaFile,
String vocabularyConfig) {
return validateCCDAImplementation(validationObjective, referenceFileName, ccdaFile, vocabularyConfig);
}

private ValidationResultsDto validateCCDAImplementation(String validationObjective, String referenceFileName,
MultipartFile ccdaFile, String vocabularyConfig) {
ValidationResultsDto resultsDto = new ValidationResultsDto();
ValidationResultsMetaData resultsMetaData = new ValidationResultsMetaData();
List<RefCCDAValidationResult> validatorResults = new ArrayList<>();
try {
validatorResults = runValidators(validationObjective, referenceFileName, ccdaFile);
validatorResults = runValidators(validationObjective, referenceFileName, ccdaFile, vocabularyConfig);
resultsMetaData = buildValidationMedata(validatorResults, validationObjective);
resultsMetaData.setCcdaFileName(ccdaFile.getOriginalFilename());
resultsMetaData.setCcdaFileContents(new String(ccdaFile.getBytes()));
Expand Down Expand Up @@ -91,7 +102,8 @@ private static void processValidateCCDAException(ValidationResultsMetaData resul
}

private List<RefCCDAValidationResult> runValidators(String validationObjective, String referenceFileName,
MultipartFile ccdaFile) throws SAXException, Exception {
MultipartFile ccdaFile, String vocabularyConfig)
throws SAXException, Exception {
List<RefCCDAValidationResult> validatorResults = new ArrayList<>();
InputStream ccdaFileInputStream = null;
try {
Expand All @@ -107,12 +119,17 @@ private List<RefCCDAValidationResult> runValidators(String validationObjective,
boolean isSchemaErrorInMdhtResults = mdhtResultsHaveSchemaError(mdhtResults);
boolean isObjectiveAllowingVocabularyValidation = objectiveAllowsVocabularyValidation(validationObjective);
if (!isSchemaErrorInMdhtResults && isObjectiveAllowingVocabularyValidation) {
List<RefCCDAValidationResult> vocabResults = doVocabularyValidation(validationObjective, referenceFileName, ccdaFileContents);
if(vocabularyConfig == null || vocabularyConfig.isEmpty()) {
logger.warn("Invalid vocabularyConfig of '" + vocabularyConfig != null ? vocabularyConfig : "null" + "' "
+ "received. Assigned default config of '" + VocabularyConstants.Config.DEFAULT + "'.");
vocabularyConfig = VocabularyConstants.Config.DEFAULT;
}
List<RefCCDAValidationResult> vocabResults = doVocabularyValidation(validationObjective,
referenceFileName, ccdaFileContents, vocabularyConfig);
if(vocabResults != null && !vocabResults.isEmpty()) {
logger.info("Adding Vocabulary results");
validatorResults.addAll(vocabResults);
}

}
if(objectiveAllowsContentValidation(validationObjective)) {
List<RefCCDAValidationResult> contentResults = doContentValidation(validationObjective, referenceFileName, ccdaFileContents);
if(contentResults != null && !contentResults.isEmpty()) {
Expand All @@ -138,7 +155,7 @@ private List<RefCCDAValidationResult> runValidators(String validationObjective,
}
return validatorResults;
}

private boolean mdhtResultsHaveSchemaError(List<RefCCDAValidationResult> mdhtResults) {
for(RefCCDAValidationResult result : mdhtResults){
if(result.isSchemaError()){
Expand All @@ -164,9 +181,10 @@ private List<RefCCDAValidationResult> doMDHTValidation(String validationObjectiv
return referenceCCDAValidator.validateFile(validationObjective, referenceFileName, ccdaFileContents);
}

private ArrayList<RefCCDAValidationResult> doVocabularyValidation(String validationObjective, String referenceFileName, String ccdaFileContents) throws SAXException {
private ArrayList<RefCCDAValidationResult> doVocabularyValidation(String validationObjective,
String referenceFileName, String ccdaFileContents, String vocabularyConfig) throws SAXException {
logger.info("Attempting Vocabulary validation...");
return vocabularyCCDAValidator.validateFile(validationObjective, referenceFileName, ccdaFileContents);
return vocabularyCCDAValidator.validateFile(validationObjective, referenceFileName, ccdaFileContents, vocabularyConfig);
}

private List<RefCCDAValidationResult> doContentValidation(String validationObjective, String referenceFileName, String ccdaFileContents) throws SAXException {
Expand Down
Loading

0 comments on commit 852dc26

Please sign in to comment.