1 package ca.uhn.fhir.validation;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import java.io.InputStream;
24 import java.io.StringReader;
25 import java.util.HashMap;
26 import java.util.Locale;
27 import java.util.Map;
28
29 import javax.xml.transform.stream.StreamSource;
30
31 import org.oclc.purl.dsdl.svrl.SchematronOutputType;
32
33 import ca.uhn.fhir.model.api.Bundle;
34 import ca.uhn.fhir.model.api.BundleEntry;
35 import ca.uhn.fhir.model.api.IResource;
36 import ca.uhn.fhir.model.dstu.resource.OperationOutcome.Issue;
37 import ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum;
38
39 import com.phloc.commons.error.IResourceError;
40 import com.phloc.commons.error.IResourceErrorGroup;
41 import com.phloc.schematron.ISchematronResource;
42 import com.phloc.schematron.SchematronHelper;
43 import com.phloc.schematron.xslt.SchematronResourceSCH;
44
45 public class SchematronBaseValidator implements IValidator {
46
47 private Map<Class<? extends IResource>, ISchematronResource> myClassToSchematron = new HashMap<Class<? extends IResource>, ISchematronResource>();
48
49 @Override
50 public void validateResource(ValidationContext<IResource> theCtx) {
51
52 ISchematronResource sch = getSchematron(theCtx);
53 StreamSource source = new StreamSource(new StringReader(theCtx.getXmlEncodedResource()));
54
55 SchematronOutputType results = SchematronHelper.applySchematron(sch, source);
56 if (results == null) {
57 return;
58 }
59
60 IResourceErrorGroup errors = SchematronHelper.convertToResourceErrorGroup(results, theCtx.getFhirContext().getResourceDefinition(theCtx.getResource()).getBaseDefinition().getName());
61
62 if (errors.getAllErrors().containsOnlySuccess()) {
63 return;
64 }
65
66 for (IResourceError next : errors.getAllErrors().getAllResourceErrors()) {
67 Issue issue = theCtx.getOperationOutcome().addIssue();
68 switch (next.getErrorLevel()) {
69 case ERROR:
70 issue.setSeverity(IssueSeverityEnum.ERROR);
71 break;
72 case FATAL_ERROR:
73 issue.setSeverity(IssueSeverityEnum.FATAL);
74 break;
75 case WARN:
76 issue.setSeverity(IssueSeverityEnum.WARNING);
77 break;
78 case INFO:
79 case SUCCESS:
80 continue;
81 }
82
83 issue.getDetails().setValue(next.getAsString(Locale.getDefault()));
84 }
85
86 }
87
88 private ISchematronResource getSchematron(ValidationContext<IResource> theCtx) {
89 Class<? extends IResource> resource = theCtx.getResource().getClass();
90 Class<? extends IResource> baseResourceClass = theCtx.getFhirContext().getResourceDefinition(resource).getBaseDefinition().getImplementingClass();
91
92 return getSchematronAndCache(theCtx, "dstu", baseResourceClass);
93 }
94
95 private ISchematronResource getSchematronAndCache(ValidationContext<IResource> theCtx, String theVersion, Class<? extends IResource> theClass) {
96 synchronized (myClassToSchematron) {
97 ISchematronResource retVal = myClassToSchematron.get(theClass);
98 if (retVal != null) {
99 return retVal;
100 }
101
102 String pathToBase = "ca/uhn/fhir/model/" + theVersion + "/schema/" + theCtx.getFhirContext().getResourceDefinition(theCtx.getResource()).getBaseDefinition().getName().toLowerCase()
103 + ".sch";
104 InputStream baseIs = FhirValidator.class.getClassLoader().getResourceAsStream(pathToBase);
105 if (baseIs == null) {
106 throw new ValidationFailureException("No schematron found for resource type: "
107 + theCtx.getFhirContext().getResourceDefinition(theCtx.getResource()).getBaseDefinition().getImplementingClass().getCanonicalName());
108 }
109
110 retVal = SchematronResourceSCH.fromClassPath(pathToBase);
111 myClassToSchematron.put(theClass, retVal);
112 return retVal;
113 }
114 }
115
116 @Override
117 public void validateBundle(ValidationContext<Bundle> theContext) {
118 for (BundleEntry next : theContext.getResource().getEntries()) {
119 if (next.getResource() != null) {
120 ValidationContext<IResource> ctx = ValidationContext.newChild(theContext, next.getResource());
121 validateResource(ctx);
122 }
123 }
124 }
125
126 }