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.i18n.Msg;
023import ca.uhn.fhir.model.api.annotation.Child;
024import org.hl7.fhir.instance.model.api.IBase;
025import org.hl7.fhir.instance.model.api.IBaseReference;
026
027import java.util.List;
028import java.util.Map;
029import java.util.Map.Entry;
030import java.util.Optional;
031import java.util.Set;
032
033public abstract class BaseRuntimeChildDefinition {
034
035        private BaseRuntimeChildDefinition myReplacedParentDefinition;
036
037        public abstract IAccessor getAccessor();
038
039        public abstract BaseRuntimeElementDefinition<?> getChildByName(String theName);
040
041        public abstract BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IBase> theType);
042
043        public abstract String getChildNameByDatatype(Class<? extends IBase> theDatatype);
044
045        public abstract String getElementName();
046
047        public String getExtensionUrl() {
048                return null;
049        }
050
051        public Object getInstanceConstructorArguments() {
052                return null;
053        }
054
055        public abstract int getMax();
056
057        public abstract int getMin();
058
059        public abstract IMutator getMutator();
060
061        public abstract Set<String> getValidChildNames();
062
063        public abstract boolean isSummary();
064
065        abstract void sealAndInitialize(
066                        FhirContext theContext,
067                        Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions);
068
069        @Override
070        public String toString() {
071                return getClass().getSimpleName() + "[" + getElementName() + "]";
072        }
073
074        public BaseRuntimeChildDefinition getReplacedParentDefinition() {
075                return myReplacedParentDefinition;
076        }
077
078        public void setReplacedParentDefinition(BaseRuntimeChildDefinition myReplacedParentDefinition) {
079                this.myReplacedParentDefinition = myReplacedParentDefinition;
080        }
081
082        public boolean isMultipleCardinality() {
083                return this.getMax() > 1 || this.getMax() == Child.MAX_UNLIMITED;
084        }
085
086        public interface IAccessor {
087                List<IBase> getValues(IBase theTarget);
088
089                default <T extends IBase> Optional<T> getFirstValueOrNull(IBase theTarget) {
090                        return (Optional<T>) getValues(theTarget).stream().findFirst();
091                }
092        }
093
094        public interface IMutator {
095                void addValue(IBase theTarget, IBase theValue);
096
097                void setValue(IBase theTarget, IBase theValue);
098
099                /**
100                 * Remove an item from a list of values
101                 * @param theTarget field to remove the item from (e.g. patient.name)
102                 * @param theIndex the index of the item to be removed (e.g. 1 for patient.name[1])
103                 */
104                default void remove(IBase theTarget, int theIndex) {
105                        // implemented in subclasses
106                }
107        }
108
109        BaseRuntimeElementDefinition<?> findResourceReferenceDefinition(
110                        Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
111                for (Entry<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> next :
112                                theClassToElementDefinitions.entrySet()) {
113                        if (IBaseReference.class.isAssignableFrom(next.getKey())) {
114                                return next.getValue();
115                        }
116                }
117
118                // Shouldn't happen
119                throw new IllegalStateException(Msg.code(1692) + "Unable to find reference type");
120        }
121
122        // public String getExtensionUrl() {
123        // return null;
124        // }
125}