View Javadoc
1   package ca.uhn.fhir.validation;
2   
3   /*
4    * #%L
5    * HAPI FHIR - Core Library
6    * %%
7    * Copyright (C) 2014 University Health Network
8    * %%
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   * 
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   * 
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * #L%
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 }