001/*
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2023 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.context;
021
022import ca.uhn.fhir.model.api.annotation.Child;
023import ca.uhn.fhir.model.api.annotation.Description;
024import org.hl7.fhir.instance.model.api.IBase;
025import org.hl7.fhir.instance.model.api.IBaseReference;
026import org.hl7.fhir.instance.model.api.IBaseResource;
027
028import java.lang.reflect.Field;
029import java.util.ArrayList;
030import java.util.Collections;
031import java.util.HashSet;
032import java.util.List;
033import java.util.Map;
034import java.util.Set;
035
036public class RuntimeChildResourceDefinition extends BaseRuntimeDeclaredChildDefinition {
037
038        private BaseRuntimeElementDefinition<?> myRuntimeDef;
039        private List<Class<? extends IBaseResource>> myResourceTypes;
040        private Set<String> myValidChildNames;
041
042        /**
043         * Constructor
044         */
045        public RuntimeChildResourceDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, List<Class<? extends IBaseResource>> theResourceTypes) {
046                super(theField, theChildAnnotation, theDescriptionAnnotation, theElementName);
047                myResourceTypes = theResourceTypes;
048
049                if (theResourceTypes == null || theResourceTypes.isEmpty()) {
050                        myResourceTypes = new ArrayList<>();
051                        myResourceTypes.add(IBaseResource.class);
052                }
053        }
054
055        @Override
056        public String getChildNameByDatatype(Class<? extends IBase> theDatatype) {
057                if (IBaseReference.class.isAssignableFrom(theDatatype)) {
058                        return getElementName();
059                }
060                return null;
061        }
062
063        @Override
064        public BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IBase> theDatatype) {
065                if (IBaseReference.class.isAssignableFrom(theDatatype)) {
066                        return myRuntimeDef;
067                }
068                return null;
069        }
070
071        @Override
072        public Set<String> getValidChildNames() {
073                return myValidChildNames;
074        }
075
076        @Override
077        public BaseRuntimeElementDefinition<?> getChildByName(String theName) {
078                return myRuntimeDef;
079        }
080
081        @Override
082        void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
083                myRuntimeDef = findResourceReferenceDefinition(theClassToElementDefinitions);
084
085                myValidChildNames = new HashSet<String>();
086                myValidChildNames.add(getElementName());
087                
088                /*
089                 * [elementName]Resource is not actually valid FHIR but we've encountered it in the wild
090                 * so we'll accept it just to be nice
091                 */
092                myValidChildNames.add(getElementName() + "Resource");
093
094                /*
095                 * Below has been disabled- We used to allow field names to contain the name of the resource
096                 * that they accepted. This wasn't valid but we accepted it just to be flexible because there
097                 * were some bad examples containing this. This causes conflicts with actual field names in 
098                 * recent definitions though, so it has been disabled as of HAPI 0.9 
099                 */
100//              for (Class<? extends IBaseResource> next : myResourceTypes) {
101//                      if (next == IResource.class) {
102//                              for (Entry<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> nextEntry : theClassToElementDefinitions.entrySet()) {
103//                                      if (IResource.class.isAssignableFrom(nextEntry.getKey())) {
104//                                              RuntimeResourceDefinition nextDef = (RuntimeResourceDefinition) nextEntry.getValue();
105//                                              myValidChildNames.add(getElementName() + nextDef.getName());
106//                                      }
107//                              }
108//                      } 
109//                      else {
110//                              RuntimeResourceDefinition nextDef = (RuntimeResourceDefinition) theClassToElementDefinitions.get(next);
111//                              if (nextDef == null) {
112//                                      throw new ConfigurationException(Msg.code(1691) + "Can't find child of type: " + next.getCanonicalName() + " in " + getField().getDeclaringClass());
113//                              }
114//                              myValidChildNames.add(getElementName() + nextDef.getName());
115//                      }
116//              }
117
118                myResourceTypes = Collections.unmodifiableList(myResourceTypes);
119                myValidChildNames = Collections.unmodifiableSet(myValidChildNames);
120        }
121
122        public List<Class<? extends IBaseResource>> getResourceTypes() {
123                return myResourceTypes;
124        }
125
126        @Override
127        public String toString() {
128                return getClass().getSimpleName() + "[" + getElementName() + "]";
129        }
130}