View Javadoc
1   package ca.uhn.fhir.util;
2   
3   import static org.apache.commons.lang3.StringUtils.isNotBlank;
4   
5   /*
6    * #%L
7    * HAPI FHIR - Core Library
8    * %%
9    * Copyright (C) 2014 - 2018 University Health Network
10   * %%
11   * Licensed under the Apache License, Version 2.0 (the "License");
12   * you may not use this file except in compliance with the License.
13   * You may obtain a copy of the License at
14   * 
15   *      http://www.apache.org/licenses/LICENSE-2.0
16   * 
17   * Unless required by applicable law or agreed to in writing, software
18   * distributed under the License is distributed on an "AS IS" BASIS,
19   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   * See the License for the specific language governing permissions and
21   * limitations under the License.
22   * #L%
23   */
24  
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import org.apache.commons.lang3.tuple.Pair;
29  import org.hl7.fhir.instance.model.api.*;
30  
31  import ca.uhn.fhir.context.*;
32  import ca.uhn.fhir.rest.api.RequestTypeEnum;
33  
34  /**
35   * Fetch resources from a bundle
36   */
37  public class BundleUtil {
38  
39  	/**
40  	 * @return Returns <code>null</code> if the link isn't found or has no value
41  	 */
42  	public static String getLinkUrlOfType(FhirContext theContext, IBaseBundle theBundle, String theLinkRelation) {
43  		RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
44  		BaseRuntimeChildDefinition entryChild = def.getChildByName("link");
45  		List<IBase> links = entryChild.getAccessor().getValues(theBundle);
46  		for (IBase nextLink : links) {
47  
48  			boolean isRightRel = false;
49  			BaseRuntimeElementCompositeDefinition relDef = (BaseRuntimeElementCompositeDefinition) theContext.getElementDefinition(nextLink.getClass());
50  			BaseRuntimeChildDefinition relChild = relDef.getChildByName("relation");
51  			List<IBase> relValues = relChild.getAccessor().getValues(nextLink);
52  			for (IBase next : relValues) {
53  				IPrimitiveType<?> nextValue = (IPrimitiveType<?>)next;
54  				if (theLinkRelation.equals(nextValue.getValueAsString())) {
55  					isRightRel = true;
56  				}
57  			}
58  
59  			if (!isRightRel) {
60  				continue;
61  			}
62  
63  			BaseRuntimeElementCompositeDefinition linkDef = (BaseRuntimeElementCompositeDefinition) theContext.getElementDefinition(nextLink.getClass());
64  			BaseRuntimeChildDefinition urlChild = linkDef.getChildByName("url");
65  			List<IBase> values = urlChild.getAccessor().getValues(nextLink);
66  			for (IBase nextUrl : values) {
67  				IPrimitiveType<?> nextValue = (IPrimitiveType<?>)nextUrl;
68  				if (isNotBlank(nextValue.getValueAsString())) {
69  					return nextValue.getValueAsString();
70  				}
71  			}
72  
73  		}
74  
75  		return null;
76  	}
77  
78  	@SuppressWarnings("unchecked")
79  	public static List<Pair<String, IBaseResource>> getBundleEntryUrlsAndResources(FhirContext theContext, IBaseBundle theBundle) {
80  		RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
81  		BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
82  		List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
83  
84  		BaseRuntimeElementCompositeDefinition<?> entryChildElem = (BaseRuntimeElementCompositeDefinition<?>) entryChild.getChildByName("entry");
85  		BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
86  		
87  		BaseRuntimeChildDefinition requestChild = entryChildElem.getChildByName("request");
88  		BaseRuntimeElementCompositeDefinition<?> requestDef = (BaseRuntimeElementCompositeDefinition<?>) requestChild.getChildByName("request");
89  		
90  		BaseRuntimeChildDefinition urlChild = requestDef.getChildByName("url");
91  
92  		List<Pair<String, IBaseResource>> retVal = new ArrayList<>(entries.size());
93  		for (IBase nextEntry : entries) {
94  			
95  			String url = null;
96  			IBaseResource resource = null;
97  			
98  			for (IBase nextEntryValue : requestChild.getAccessor().getValues(nextEntry)) {
99  				for (IBase nextUrlValue : urlChild.getAccessor().getValues(nextEntryValue)) {
100 					url = ((IPrimitiveType<String>)nextUrlValue).getValue();
101 				}
102 			}
103 			
104 			// Should return 0..1 only
105 			for (IBase nextValue : resourceChild.getAccessor().getValues(nextEntry)) {
106 				resource = (IBaseResource) nextValue;
107 			}
108 			
109 			retVal.add(Pair.of(url, resource));
110 		}
111 		
112 		return retVal;		
113 	}
114 	
115 	public static String getBundleType(FhirContext theContext, IBaseBundle theBundle) {
116 		RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
117 		BaseRuntimeChildDefinition entryChild = def.getChildByName("type");
118 		List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
119 		if (entries.size() > 0) {
120 			IPrimitiveType<?> typeElement = (IPrimitiveType<?>) entries.get(0);
121 			return typeElement.getValueAsString();
122 		}
123 		return null;
124 	}
125 
126 	public static Integer getTotal(FhirContext theContext, IBaseBundle theBundle) {
127 		RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
128 		BaseRuntimeChildDefinition entryChild = def.getChildByName("total");
129 		List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
130 		if (entries.size() > 0) {
131 			IPrimitiveType<Number> typeElement = (IPrimitiveType<Number>) entries.get(0);
132 			if (typeElement != null && typeElement.getValue() != null) {
133 				return typeElement.getValue().intValue();
134 			}
135 		}
136 		return null;
137 	}
138 
139 	/**
140 	 * Extract all of the resources from a given bundle
141 	 */
142 	public static List<BundleEntryParts> toListOfEntries(FhirContext theContext, IBaseBundle theBundle) {
143 		List<BundleEntryParts> retVal = new ArrayList<>();
144 
145 		RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
146 		BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
147 		List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
148 
149 		BaseRuntimeElementCompositeDefinition<?> entryChildElem = (BaseRuntimeElementCompositeDefinition<?>) entryChild.getChildByName("entry");
150 		
151 		BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
152 		BaseRuntimeChildDefinition requestChild = entryChildElem.getChildByName("request");
153 		BaseRuntimeElementCompositeDefinition<?>  requestElem = (BaseRuntimeElementCompositeDefinition<?>) requestChild.getChildByName("request");
154 		BaseRuntimeChildDefinition urlChild = requestElem.getChildByName("url");
155 		BaseRuntimeChildDefinition methodChild = requestElem.getChildByName("method");
156 		
157 		IBaseResource resource = null;
158 		String url = null;
159 		RequestTypeEnum requestType = null;
160 		
161 		for (IBase nextEntry : entries) {
162 			for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
163 				resource = (IBaseResource) next;
164 			}
165 			for (IBase nextRequest : requestChild.getAccessor().getValues(nextEntry)) {
166 				for (IBase nextUrl : urlChild.getAccessor().getValues(nextRequest)) {
167 					url = ((IPrimitiveType<?>)nextUrl).getValueAsString();
168 				}
169 				for (IBase nextUrl : methodChild.getAccessor().getValues(nextRequest)) {
170 					String methodString = ((IPrimitiveType<?>)nextUrl).getValueAsString();
171 					if (isNotBlank(methodString)) {
172 						requestType = RequestTypeEnum.valueOf(methodString);
173 					}
174 				}
175 			}
176 
177 			/* 
178 			 * All 3 might be null - That's ok because we still want to know the
179 			 * order in the original bundle.
180 			 */
181 			retVal.add(new BundleEntryParts(requestType, url, resource));
182 		}
183 
184 		
185 		return retVal;
186 	}
187 	
188 	/**
189 	 * Extract all of the resources from a given bundle
190 	 */
191 	public static List<IBaseResource> toListOfResources(FhirContext theContext, IBaseBundle theBundle) {
192 		return toListOfResourcesOfType(theContext, theBundle, null);
193 	}
194 
195 	/**
196 	 * Extract all of the resources of a given type from a given bundle 
197 	 */
198 	@SuppressWarnings("unchecked")
199 	public static <T extends IBaseResource> List<T> toListOfResourcesOfType(FhirContext theContext, IBaseBundle theBundle, Class<T> theTypeToInclude) {
200 		List<T> retVal = new ArrayList<>();
201 
202 		RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
203 		BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
204 		List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
205 
206 		BaseRuntimeElementCompositeDefinition<?> entryChildElem = (BaseRuntimeElementCompositeDefinition<?>) entryChild.getChildByName("entry");
207 		BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
208 		for (IBase nextEntry : entries) {
209 			for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
210 				if (theTypeToInclude != null && !theTypeToInclude.isAssignableFrom(next.getClass())) {
211 					continue;
212 				}
213 				retVal.add((T) next);
214 			}
215 		}
216 
217 		return retVal;
218 	}
219 
220 	public static class BundleEntryParts
221 	{
222 		private final RequestTypeEnum myRequestType;
223 		private final IBaseResource myResource;
224 		private final String myUrl;
225 		BundleEntryParts(RequestTypeEnum theRequestType, String theUrl, IBaseResource theResource) {
226 			super();
227 			myRequestType = theRequestType;
228 			myUrl = theUrl;
229 			myResource = theResource;
230 		}
231 		public RequestTypeEnum getRequestType() {
232 			return myRequestType;
233 		}
234 		public IBaseResource getResource() {
235 			return myResource;
236 		}
237 		public String getUrl() {
238 			return myUrl;
239 		}
240 	}
241 
242 }