001/*
002 * #%L
003 * HAPI FHIR - Core Library
004 * %%
005 * Copyright (C) 2014 - 2024 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.slf4j.Logger;
026import org.slf4j.LoggerFactory;
027
028import java.lang.reflect.Field;
029import java.lang.reflect.Modifier;
030import java.util.Collections;
031import java.util.Map;
032import java.util.Set;
033
034public abstract class BaseRuntimeChildDatatypeDefinition extends BaseRuntimeDeclaredChildDefinition {
035        Logger ourLog = LoggerFactory.getLogger(BaseRuntimeChildDatatypeDefinition.class);
036
037        private Class<? extends IBase> myDatatype;
038
039        private BaseRuntimeElementDefinition<?> myElementDefinition;
040
041        public BaseRuntimeChildDatatypeDefinition(
042                        Field theField,
043                        String theElementName,
044                        Child theChildAnnotation,
045                        Description theDescriptionAnnotation,
046                        Class<? extends IBase> theDatatype) {
047                super(theField, theChildAnnotation, theDescriptionAnnotation, theElementName);
048                // should use RuntimeChildAny
049                assert Modifier.isInterface(theDatatype.getModifiers()) == false
050                                : "Type of " + theDatatype + " shouldn't be here";
051                assert Modifier.isAbstract(theDatatype.getModifiers()) == false
052                                : "Type of " + theDatatype + " shouldn't be here";
053                myDatatype = theDatatype;
054        }
055
056        /**
057         * If this child has a bound type, this method will return the Enum type that
058         * it is bound to. Otherwise, will return <code>null</code>.
059         */
060        public Class<? extends Enum<?>> getBoundEnumType() {
061                return null;
062        }
063
064        @Override
065        public BaseRuntimeElementDefinition<?> getChildByName(String theName) {
066                if (getElementName().equals(theName)) {
067                        return myElementDefinition;
068                }
069                return null;
070        }
071
072        @Override
073        public BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IBase> theDatatype) {
074                Class<?> nextType = theDatatype;
075                while (nextType.equals(Object.class) == false) {
076                        if (myDatatype.equals(nextType)) {
077                                return myElementDefinition;
078                        }
079                        nextType = nextType.getSuperclass();
080                }
081                return null;
082        }
083
084        @Override
085        public String getChildNameByDatatype(Class<? extends IBase> theDatatype) {
086                Class<?> nextType = theDatatype;
087                while (nextType.equals(Object.class) == false) {
088                        if (myDatatype.equals(nextType)) {
089                                return getElementName();
090                        }
091                        nextType = nextType.getSuperclass();
092                }
093                return null;
094        }
095
096        public Class<? extends IBase> getDatatype() {
097                return myDatatype;
098        }
099
100        @Override
101        public Set<String> getValidChildNames() {
102                return Collections.singleton(getElementName());
103        }
104
105        @Override
106        void sealAndInitialize(
107                        FhirContext theContext,
108                        Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
109                myElementDefinition = theClassToElementDefinitions.get(getDatatype());
110                if (myElementDefinition == null) {
111                        myElementDefinition = theContext.getElementDefinition(getDatatype());
112                }
113                assert myElementDefinition != null : "Unknown type: " + getDatatype();
114        }
115
116        @Override
117        public String toString() {
118                return getClass().getSimpleName() + "[" + getElementName() + "]";
119        }
120}