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 - 2017 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.IBase;
030import org.hl7.fhir.instance.model.api.IBaseBundle;
031import org.hl7.fhir.instance.model.api.IBaseResource;
032import org.hl7.fhir.instance.model.api.IPrimitiveType;
033
034import ca.uhn.fhir.context.BaseRuntimeChildDefinition;
035import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
036import ca.uhn.fhir.context.FhirContext;
037import ca.uhn.fhir.context.RuntimeResourceDefinition;
038import ca.uhn.fhir.rest.api.RequestTypeEnum;
039
040/**
041 * Fetch resources from a bundle
042 */
043public class BundleUtil {
044
045        @SuppressWarnings("unchecked")
046        public static List<Pair<String, IBaseResource>> getBundleEntryUrlsAndResources(FhirContext theContext, IBaseBundle theBundle) {
047                RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
048                BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
049                List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
050
051                BaseRuntimeElementCompositeDefinition<?> entryChildElem = (BaseRuntimeElementCompositeDefinition<?>) entryChild.getChildByName("entry");
052                BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
053                
054                BaseRuntimeChildDefinition requestChild = entryChildElem.getChildByName("request");
055                BaseRuntimeElementCompositeDefinition<?> requestDef = (BaseRuntimeElementCompositeDefinition<?>) requestChild.getChildByName("request");
056                
057                BaseRuntimeChildDefinition urlChild = requestDef.getChildByName("url");
058
059                List<Pair<String, IBaseResource>> retVal = new ArrayList<Pair<String,IBaseResource>>(entries.size());
060                for (IBase nextEntry : entries) {
061                        
062                        String url = null;
063                        IBaseResource resource = null;
064                        
065                        for (IBase nextEntryValue : requestChild.getAccessor().getValues(nextEntry)) {
066                                for (IBase nextUrlValue : urlChild.getAccessor().getValues(nextEntryValue)) {
067                                        url = ((IPrimitiveType<String>)nextUrlValue).getValue();
068                                }
069                        }
070                        
071                        // Should return 0..1 only
072                        for (IBase nextValue : resourceChild.getAccessor().getValues(nextEntry)) {
073                                resource = (IBaseResource) nextValue;
074                        }
075                        
076                        retVal.add(Pair.of(url, resource));
077                }
078                
079                return retVal;          
080        }
081        
082        public static String getBundleType(FhirContext theContext, IBaseBundle theBundle) {
083                RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
084                BaseRuntimeChildDefinition entryChild = def.getChildByName("type");
085                List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
086                if (entries.size() > 0) {
087                        IPrimitiveType<?> typeElement = (IPrimitiveType<?>) entries.get(0);
088                        return typeElement.getValueAsString();
089                }
090                return null;
091        }
092
093        /**
094         * Extract all of the resources from a given bundle
095         */
096        public static List<BundleEntryParts> toListOfEntries(FhirContext theContext, IBaseBundle theBundle) {
097                List<BundleEntryParts> retVal = new ArrayList<BundleEntryParts>();
098
099                RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
100                BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
101                List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
102
103                BaseRuntimeElementCompositeDefinition<?> entryChildElem = (BaseRuntimeElementCompositeDefinition<?>) entryChild.getChildByName("entry");
104                
105                BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
106                BaseRuntimeChildDefinition requestChild = entryChildElem.getChildByName("request");
107                BaseRuntimeElementCompositeDefinition<?>  requestElem = (BaseRuntimeElementCompositeDefinition<?>) requestChild.getChildByName("request");
108                BaseRuntimeChildDefinition urlChild = requestElem.getChildByName("url");
109                BaseRuntimeChildDefinition methodChild = requestElem.getChildByName("method");
110                
111                IBaseResource resource = null;
112                String url = null;
113                RequestTypeEnum requestType = null;
114                
115                for (IBase nextEntry : entries) {
116                        for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
117                                resource = (IBaseResource) next;
118                        }
119                        for (IBase nextRequest : requestChild.getAccessor().getValues(nextEntry)) {
120                                for (IBase nextUrl : urlChild.getAccessor().getValues(nextRequest)) {
121                                        url = ((IPrimitiveType<?>)nextUrl).getValueAsString();
122                                }
123                                for (IBase nextUrl : methodChild.getAccessor().getValues(nextRequest)) {
124                                        String methodString = ((IPrimitiveType<?>)nextUrl).getValueAsString();
125                                        if (isNotBlank(methodString)) {
126                                                requestType = RequestTypeEnum.valueOf(methodString);
127                                        }
128                                }
129                        }
130
131                        /* 
132                         * All 3 might be null - That's ok because we still want to know the
133                         * order in the original bundle.
134                         */
135                        retVal.add(new BundleEntryParts(requestType, url, resource));
136                }
137
138                
139                return retVal;
140        }
141        
142        /**
143         * Extract all of the resources from a given bundle
144         */
145        public static List<IBaseResource> toListOfResources(FhirContext theContext, IBaseBundle theBundle) {
146                List<IBaseResource> retVal = new ArrayList<IBaseResource>();
147
148                RuntimeResourceDefinition def = theContext.getResourceDefinition(theBundle);
149                BaseRuntimeChildDefinition entryChild = def.getChildByName("entry");
150                List<IBase> entries = entryChild.getAccessor().getValues(theBundle);
151
152                BaseRuntimeElementCompositeDefinition<?> entryChildElem = (BaseRuntimeElementCompositeDefinition<?>) entryChild.getChildByName("entry");
153                BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
154                for (IBase nextEntry : entries) {
155                        for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
156                                retVal.add((IBaseResource) next);
157                        }
158                }
159
160                return retVal;
161        }
162
163        public static class BundleEntryParts
164        {
165                private final RequestTypeEnum myRequestType;
166                private final IBaseResource myResource;
167                private final String myUrl;
168                public BundleEntryParts(RequestTypeEnum theRequestType, String theUrl, IBaseResource theResource) {
169                        super();
170                        myRequestType = theRequestType;
171                        myUrl = theUrl;
172                        myResource = theResource;
173                }
174                public RequestTypeEnum getRequestType() {
175                        return myRequestType;
176                }
177                public IBaseResource getResource() {
178                        return myResource;
179                }
180                public String getUrl() {
181                        return myUrl;
182                }
183        }
184
185}