001package ca.uhn.fhir.util; 002 003import static org.apache.commons.lang3.StringUtils.isNotBlank; 004 005/* 006 * #%L 007 * HAPI FHIR - Core Library 008 * %% 009 * Copyright (C) 2014 - 2018 University Health Network 010 * %% 011 * Licensed under the Apache License, Version 2.0 (the "License"); 012 * you may not use this file except in compliance with the License. 013 * You may obtain a copy of the License at 014 * 015 * http://www.apache.org/licenses/LICENSE-2.0 016 * 017 * Unless required by applicable law or agreed to in writing, software 018 * distributed under the License is distributed on an "AS IS" BASIS, 019 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 020 * See the License for the specific language governing permissions and 021 * limitations under the License. 022 * #L% 023 */ 024 025import java.util.ArrayList; 026import java.util.List; 027 028import org.apache.commons.lang3.tuple.Pair; 029import org.hl7.fhir.instance.model.api.*; 030 031import ca.uhn.fhir.context.*; 032import ca.uhn.fhir.rest.api.RequestTypeEnum; 033 034/** 035 * Fetch resources from a bundle 036 */ 037public class BundleUtil { 038 039 /** 040 * @return Returns <code>null</code> if the link isn't found or has no value 041 */ 042 public static String getLinkUrlOfType(FhirContext theContext, IBaseBundle theBundle, String theLinkRelation) { 043 RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle); 044 BaseRuntimeChildDefinition entryChild = def.getChildByName("link"); 045 List<IBase> links = entryChild.getAccessor().getValues(theBundle); 046 for (IBase nextLink : links) { 047 048 boolean isRightRel = false; 049 BaseRuntimeElementCompositeDefinition relDef = (BaseRuntimeElementCompositeDefinition) theContext.getElementDefinition(nextLink.getClass()); 050 BaseRuntimeChildDefinition relChild = relDef.getChildByName("relation"); 051 List<IBase> relValues = relChild.getAccessor().getValues(nextLink); 052 for (IBase next : relValues) { 053 IPrimitiveType<?> nextValue = (IPrimitiveType<?>)next; 054 if (theLinkRelation.equals(nextValue.getValueAsString())) { 055 isRightRel = true; 056 } 057 } 058 059 if (!isRightRel) { 060 continue; 061 } 062 063 BaseRuntimeElementCompositeDefinition linkDef = (BaseRuntimeElementCompositeDefinition) theContext.getElementDefinition(nextLink.getClass()); 064 BaseRuntimeChildDefinition urlChild = linkDef.getChildByName("url"); 065 List<IBase> values = urlChild.getAccessor().getValues(nextLink); 066 for (IBase nextUrl : values) { 067 IPrimitiveType<?> nextValue = (IPrimitiveType<?>)nextUrl; 068 if (isNotBlank(nextValue.getValueAsString())) { 069 return nextValue.getValueAsString(); 070 } 071 } 072 073 } 074 075 return null; 076 } 077 078 @SuppressWarnings("unchecked") 079 public static List<Pair<String, IBaseResource>> getBundleEntryUrlsAndResources(FhirContext theContext, IBaseBundle theBundle) { 080 RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle); 081 BaseRuntimeChildDefinition entryChild = def.getChildByName("entry"); 082 List<IBase> entries = entryChild.getAccessor().getValues(theBundle); 083 084 BaseRuntimeElementCompositeDefinition<?> entryChildElem = (BaseRuntimeElementCompositeDefinition<?>) entryChild.getChildByName("entry"); 085 BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource"); 086 087 BaseRuntimeChildDefinition requestChild = entryChildElem.getChildByName("request"); 088 BaseRuntimeElementCompositeDefinition<?> requestDef = (BaseRuntimeElementCompositeDefinition<?>) requestChild.getChildByName("request"); 089 090 BaseRuntimeChildDefinition urlChild = requestDef.getChildByName("url"); 091 092 List<Pair<String, IBaseResource>> retVal = new ArrayList<>(entries.size()); 093 for (IBase nextEntry : entries) { 094 095 String url = null; 096 IBaseResource resource = null; 097 098 for (IBase nextEntryValue : requestChild.getAccessor().getValues(nextEntry)) { 099 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 for (IBase nextEntry : entries) { 158 IBaseResource resource = null; 159 String url = null; 160 RequestTypeEnum requestType = null; 161 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}