Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add validation module for QuestionnaireAnswers
- Loading branch information
1 parent
818c404
commit 3bba0c0
Showing
7 changed files
with
374 additions
and
61 deletions.
There are no files selected for viewing
22 changes: 22 additions & 0 deletions
22
hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/IResourceLoader.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package ca.uhn.fhir.validation; | ||
|
||
import org.hl7.fhir.instance.model.api.IBaseResource; | ||
import org.hl7.fhir.instance.model.api.IIdType; | ||
|
||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; | ||
|
||
public interface IResourceLoader { | ||
|
||
/** | ||
* Load the latest version of a given resource | ||
* | ||
* @param theType | ||
* The type of the resource to load | ||
* @param theId | ||
* The ID of the resource to load | ||
* @throws ResourceNotFoundException | ||
* If the resource is not known | ||
*/ | ||
public <T extends IBaseResource> T load(Class<T> theType, IIdType theId) throws ResourceNotFoundException; | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
51 changes: 51 additions & 0 deletions
51
...hir-structures-hl7org-dstu2/src/main/java/ca/uhn/fhir/validation/BaseValidatorBridge.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package ca.uhn.fhir.validation; | ||
|
||
import java.util.List; | ||
|
||
import org.hl7.fhir.instance.model.api.IBaseResource; | ||
import org.hl7.fhir.instance.validation.ValidationMessage; | ||
|
||
import ca.uhn.fhir.model.api.Bundle; | ||
|
||
/** | ||
* Base class for a bridge between the RI validation tools and HAPI | ||
*/ | ||
abstract class BaseValidatorBridge implements IValidator { | ||
|
||
public BaseValidatorBridge() { | ||
super(); | ||
} | ||
|
||
private void doValidate(IValidationContext<?> theCtx) { | ||
List<ValidationMessage> messages = validate(theCtx); | ||
|
||
for (ValidationMessage riMessage : messages) { | ||
SingleValidationMessage hapiMessage = new SingleValidationMessage(); | ||
if (riMessage.getCol() != -1) { | ||
hapiMessage.setLocationCol(riMessage.getCol()); | ||
} | ||
if (riMessage.getLine() != -1) { | ||
hapiMessage.setLocationLine(riMessage.getLine()); | ||
} | ||
hapiMessage.setLocationString(riMessage.getLocation()); | ||
hapiMessage.setMessage(riMessage.getMessage()); | ||
if (riMessage.getLevel() != null) { | ||
hapiMessage.setSeverity(ResultSeverityEnum.fromCode(riMessage.getLevel().toCode())); | ||
} | ||
theCtx.addValidationMessage(hapiMessage); | ||
} | ||
} | ||
|
||
protected abstract List<ValidationMessage> validate(IValidationContext<?> theCtx); | ||
|
||
@Override | ||
public void validateBundle(IValidationContext<Bundle> theCtx) { | ||
doValidate(theCtx); | ||
} | ||
|
||
@Override | ||
public void validateResource(IValidationContext<IBaseResource> theCtx) { | ||
doValidate(theCtx); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
139 changes: 139 additions & 0 deletions
139
...-hl7org-dstu2/src/main/java/ca/uhn/fhir/validation/FhirQuestionnaireAnswersValidator.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package ca.uhn.fhir.validation; | ||
|
||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
|
||
import org.hl7.fhir.instance.model.OperationOutcome.IssueSeverity; | ||
import org.hl7.fhir.instance.model.Questionnaire; | ||
import org.hl7.fhir.instance.model.QuestionnaireAnswers; | ||
import org.hl7.fhir.instance.model.ValueSet; | ||
import org.hl7.fhir.instance.model.api.IBaseResource; | ||
import org.hl7.fhir.instance.model.api.IIdType; | ||
import org.hl7.fhir.instance.utils.WorkerContext; | ||
import org.hl7.fhir.instance.validation.QuestionnaireAnswersValidator; | ||
import org.hl7.fhir.instance.validation.ValidationMessage; | ||
|
||
import ca.uhn.fhir.context.RuntimeResourceDefinition; | ||
import ca.uhn.fhir.parser.IParser; | ||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; | ||
import ca.uhn.fhir.util.ResourceReferenceInfo; | ||
|
||
public class FhirQuestionnaireAnswersValidator extends BaseValidatorBridge { | ||
|
||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirQuestionnaireAnswersValidator.class); | ||
private IResourceLoader myResourceLoader; | ||
|
||
/** | ||
* Set the class which will be used to load linked resources from the <code>QuestionnaireAnswers</code>. Specifically, if the <code>QuestionnaireAnswers</code> refers to an external (non-contained) | ||
* <code>Questionnaire</code>, or to any external (non-contained) <code>ValueSet</code>, the resource loader will be used to fetch those resources during the validation. | ||
* | ||
* @param theResourceLoader | ||
* The resourceloader to use. May be <code>null</code> if no resource loader should be used (in which case any <code>QuestionaireAnswers</code> with external references will fail to | ||
* validate.) | ||
*/ | ||
public void setResourceLoader(IResourceLoader theResourceLoader) { | ||
myResourceLoader = theResourceLoader; | ||
} | ||
|
||
@Override | ||
protected List<ValidationMessage> validate(IValidationContext<?> theCtx) { | ||
Object resource = theCtx.getResource(); | ||
if (!(theCtx.getResource() instanceof IBaseResource)) { | ||
ourLog.debug("Not validating object of type {}", theCtx.getResource().getClass()); | ||
return Collections.emptyList(); | ||
} | ||
|
||
if (resource instanceof QuestionnaireAnswers) { | ||
return doValidate(theCtx, (QuestionnaireAnswers) resource); | ||
} | ||
|
||
RuntimeResourceDefinition def = theCtx.getFhirContext().getResourceDefinition((IBaseResource) resource); | ||
if ("QuestionnaireAnswers".equals(def.getName()) == false) { | ||
return Collections.emptyList(); | ||
} | ||
|
||
/* | ||
* If we have a non-RI structure, convert it | ||
*/ | ||
|
||
IParser p = theCtx.getFhirContext().newJsonParser(); | ||
String string = p.encodeResourceToString((IBaseResource) resource); | ||
QuestionnaireAnswers qa = p.parseResource(QuestionnaireAnswers.class, string); | ||
|
||
return doValidate(theCtx, qa); | ||
} | ||
|
||
private List<ValidationMessage> doValidate(IValidationContext<?> theValCtx, QuestionnaireAnswers theResource) { | ||
|
||
WorkerContext workerCtx = new WorkerContext(); | ||
ArrayList<ValidationMessage> retVal = new ArrayList<ValidationMessage>(); | ||
|
||
if (!loadReferences(theResource, workerCtx, theValCtx, retVal)) { | ||
return retVal; | ||
} | ||
|
||
QuestionnaireAnswersValidator val = new QuestionnaireAnswersValidator(workerCtx); | ||
|
||
val.validate(retVal, theResource); | ||
return retVal; | ||
} | ||
|
||
private boolean loadReferences(IBaseResource theResource, WorkerContext theWorkerCtx, IValidationContext<?> theValCtx, ArrayList<ValidationMessage> theMessages) { | ||
List<ResourceReferenceInfo> refs = theValCtx.getFhirContext().newTerser().getAllResourceReferences(theResource); | ||
|
||
List<IBaseResource> newResources = new ArrayList<IBaseResource>(); | ||
|
||
for (ResourceReferenceInfo nextRefInfo : refs) { | ||
IIdType nextRef = nextRefInfo.getResourceReference().getReferenceElement(); | ||
String resourceType = nextRef.getResourceType(); | ||
if ("ValueSet".equals(resourceType)) { | ||
if (!theWorkerCtx.getValueSets().containsKey(nextRef.getValue())) { | ||
ValueSet resource = tryToLoad(ValueSet.class, nextRef, theMessages); | ||
if (resource == null) { | ||
return false; | ||
} | ||
theWorkerCtx.getValueSets().put(nextRef.getValue(), resource); | ||
newResources.add(resource); | ||
} | ||
} else if ("Questionnaire".equals(resourceType)) { | ||
if (!theWorkerCtx.getQuestionnaires().containsKey(nextRef.getValue())) { | ||
Questionnaire resource = tryToLoad(Questionnaire.class, nextRef, theMessages); | ||
if (resource == null) { | ||
return false; | ||
} | ||
theWorkerCtx.getQuestionnaires().put(nextRef.getValue(), resource); | ||
newResources.add(resource); | ||
} | ||
} | ||
} | ||
|
||
for (IBaseResource nextAddedResource : newResources) { | ||
boolean outcome = loadReferences(nextAddedResource, theWorkerCtx, theValCtx, theMessages); | ||
if (!outcome) { | ||
return false; | ||
} | ||
} | ||
|
||
return true; | ||
} | ||
|
||
private <T extends IBaseResource> T tryToLoad(Class<T> theType, IIdType theReference, List<ValidationMessage> theMessages) { | ||
if (myResourceLoader == null) { | ||
theMessages.add(new ValidationMessage().setLevel(IssueSeverity.FATAL).setMessage("No resource loader present, could not load " + theReference)); | ||
return null; | ||
} | ||
|
||
try { | ||
T retVal = myResourceLoader.load(theType, theReference); | ||
if (retVal == null) { | ||
throw new IllegalStateException("ResourceLoader returned null. This is a bug with the resourceloader. Reference was: " + theReference); | ||
} | ||
return retVal; | ||
} catch (ResourceNotFoundException e) { | ||
theMessages.add(new ValidationMessage().setLevel(IssueSeverity.FATAL).setMessage("Reference could not be found: " + theReference)); | ||
return null; | ||
} | ||
} | ||
|
||
} |
Oops, something went wrong.