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