View Javadoc
1   package ca.uhn.fhir.util;
2   
3   /*
4    * #%L
5    * HAPI FHIR - Core Library
6    * %%
7    * Copyright (C) 2014 - 2018 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  import static org.apache.commons.lang3.StringUtils.isNotBlank;
23  
24  import java.util.List;
25  
26  import org.hl7.fhir.instance.model.api.IBase;
27  import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
28  import org.hl7.fhir.instance.model.api.IBaseResource;
29  import org.hl7.fhir.instance.model.api.IPrimitiveType;
30  
31  import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
32  import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
33  import ca.uhn.fhir.context.BaseRuntimeElementDefinition;
34  import ca.uhn.fhir.context.FhirContext;
35  import ca.uhn.fhir.context.FhirVersionEnum;
36  import ca.uhn.fhir.context.RuntimeResourceDefinition;
37  import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
38  
39  /**
40   * Utilities for dealing with OperationOutcome resources across various model versions
41   */
42  public class OperationOutcomeUtil {
43  
44  	/**
45  	 * Add an issue to an OperationOutcome
46  	 * 
47  	 * @param theCtx
48  	 *           The fhir context
49  	 * @param theOperationOutcome
50  	 *           The OO resource to add to
51  	 * @param theSeverity
52  	 *           The severity (fatal | error | warning | information)
53  	 * @param theDetails
54  	 *           The details string
55  	 * @param theCode
56  	 */
57  	public static void addIssue(FhirContext theCtx, IBaseOperationOutcome theOperationOutcome, String theSeverity, String theDetails, String theLocation, String theCode) {
58  		IBase issue = createIssue(theCtx, theOperationOutcome);
59  		populateDetails(theCtx, issue, theSeverity, theDetails, theLocation, theCode);
60  	}
61  
62  	private static IBase createIssue(FhirContext theCtx, IBaseResource theOutcome) {
63  		RuntimeResourceDefinition ooDef = theCtx.getResourceDefinition(theOutcome);
64  		BaseRuntimeChildDefinition issueChild = ooDef.getChildByName("issue");
65  		BaseRuntimeElementCompositeDefinition<?> issueElement = (BaseRuntimeElementCompositeDefinition<?>) issueChild.getChildByName("issue");
66  
67  		IBase issue = issueElement.newInstance();
68  		issueChild.getMutator().addValue(theOutcome, issue);
69  		return issue;
70  	}
71  
72  	public static String getFirstIssueDetails(FhirContext theCtx, IBaseOperationOutcome theOutcome) {
73  		return getFirstIssueStringPart(theCtx, theOutcome, "diagnostics");
74  	}
75  
76  	public static String getFirstIssueLocation(FhirContext theCtx, IBaseOperationOutcome theOutcome) {
77  		return getFirstIssueStringPart(theCtx, theOutcome, "location");
78  	}
79  
80  	private static String getFirstIssueStringPart(FhirContext theCtx, IBaseOperationOutcome theOutcome, String name) {
81  		if (theOutcome == null) {
82  			return null;
83  		}
84  
85  		RuntimeResourceDefinition ooDef = theCtx.getResourceDefinition(theOutcome);
86  		BaseRuntimeChildDefinition issueChild = ooDef.getChildByName("issue");
87  
88  		List<IBase> issues = issueChild.getAccessor().getValues(theOutcome);
89  		if (issues.isEmpty()) {
90  			return null;
91  		}
92  
93  		IBase issue = issues.get(0);
94  		BaseRuntimeElementCompositeDefinition<?> issueElement = (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(issue.getClass());
95  		BaseRuntimeChildDefinition detailsChild = issueElement.getChildByName(name);
96  
97  		List<IBase> details = detailsChild.getAccessor().getValues(issue);
98  		if (details.isEmpty()) {
99  			return null;
100 		}
101 		return ((IPrimitiveType<?>) details.get(0)).getValueAsString();
102 	}
103 
104 	/**
105 	 * Returns true if the given OperationOutcome has 1 or more Operation.issue repetitions
106 	 */
107 	public static boolean hasIssues(FhirContext theCtx, IBaseOperationOutcome theOutcome) {
108 		if (theOutcome == null) {
109 			return false;
110 		}
111 		RuntimeResourceDefinition ooDef = theCtx.getResourceDefinition(theOutcome);
112 		BaseRuntimeChildDefinition issueChild = ooDef.getChildByName("issue");
113 		return issueChild.getAccessor().getValues(theOutcome).size() > 0;
114 	}
115 
116 	public static IBaseOperationOutcome newInstance(FhirContext theCtx) {
117 		RuntimeResourceDefinition ooDef = theCtx.getResourceDefinition("OperationOutcome");
118 		try {
119 			return (IBaseOperationOutcome) ooDef.getImplementingClass().newInstance();
120 		} catch (InstantiationException e) {
121 			throw new InternalErrorException("Unable to instantiate OperationOutcome", e);
122 		} catch (IllegalAccessException e) {
123 			throw new InternalErrorException("Unable to instantiate OperationOutcome", e);
124 		}
125 	}
126 
127 	private static void populateDetails(FhirContext theCtx, IBase theIssue, String theSeverity, String theDetails, String theLocation, String theCode) {
128 		BaseRuntimeElementCompositeDefinition<?> issueElement = (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(theIssue.getClass());
129 		BaseRuntimeChildDefinition detailsChild;
130 		detailsChild = issueElement.getChildByName("diagnostics");
131 
132 		BaseRuntimeChildDefinition codeChild = issueElement.getChildByName("code");
133 		IPrimitiveType<?> codeElem = (IPrimitiveType<?>) codeChild.getChildByName("code").newInstance(codeChild.getInstanceConstructorArguments());
134 		codeElem.setValueAsString(theCode);
135 		codeChild.getMutator().addValue(theIssue, codeElem);
136 
137 		BaseRuntimeElementDefinition<?> stringDef = detailsChild.getChildByName(detailsChild.getElementName());
138 		BaseRuntimeChildDefinition severityChild = issueElement.getChildByName("severity");
139 		BaseRuntimeChildDefinition locationChild = issueElement.getChildByName("location");
140 
141 		IPrimitiveType<?> severityElem = (IPrimitiveType<?>) severityChild.getChildByName("severity").newInstance(severityChild.getInstanceConstructorArguments());
142 		severityElem.setValueAsString(theSeverity);
143 		severityChild.getMutator().addValue(theIssue, severityElem);
144 
145 		IPrimitiveType<?> string = (IPrimitiveType<?>) stringDef.newInstance();
146 		string.setValueAsString(theDetails);
147 		detailsChild.getMutator().setValue(theIssue, string);
148 
149 		if (isNotBlank(theLocation)) {
150 			IPrimitiveType<?> locationElem = (IPrimitiveType<?>) locationChild.getChildByName("location").newInstance(locationChild.getInstanceConstructorArguments());
151 			locationElem.setValueAsString(theLocation);
152 			locationChild.getMutator().addValue(theIssue, locationElem);
153 		}
154 	}
155 
156 }