001package ca.uhn.fhir.context;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2019 University Health Network
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 */
022import static org.apache.commons.lang3.StringUtils.isBlank;
023
024import java.lang.reflect.ParameterizedType;
025import java.lang.reflect.Type;
026import java.util.Map;
027
028import org.hl7.fhir.instance.model.api.IBase;
029import org.hl7.fhir.instance.model.api.IBaseDatatype;
030import org.hl7.fhir.instance.model.api.IPrimitiveType;
031
032import ca.uhn.fhir.model.api.annotation.DatatypeDef;
033import ca.uhn.fhir.model.api.annotation.ResourceDef;
034
035public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefinition<IPrimitiveType<?>> implements IRuntimeDatatypeDefinition {
036
037        private Class<?> myNativeType;
038        private BaseRuntimeElementDefinition<?> myProfileOf;
039        private Class<? extends IBaseDatatype> myProfileOfType;
040        private boolean mySpecialization;
041
042        public RuntimePrimitiveDatatypeDefinition(DatatypeDef theDef, Class<? extends IPrimitiveType<?>> theImplementingClass, boolean theStandardType) {
043                super(theDef.name(), theImplementingClass, theStandardType);
044
045                String resourceName = theDef.name();
046                if (isBlank(resourceName)) {
047                        throw new ConfigurationException("Resource type @" + ResourceDef.class.getSimpleName() + " annotation contains no resource name: " + theImplementingClass.getCanonicalName());
048                }
049
050                mySpecialization = theDef.isSpecialization();
051                myProfileOfType = theDef.profileOf();
052                if (myProfileOfType.equals(IBaseDatatype.class)) {
053                        myProfileOfType = null;
054                }
055
056                determineNativeType(theImplementingClass);
057        }
058
059        private void determineNativeType(Class<? extends IPrimitiveType<?>> theImplementingClass) {
060                Class<?> clazz = theImplementingClass;
061                while (clazz.equals(Object.class) == false) {
062                        Type type = clazz.getGenericSuperclass();
063                        if (type instanceof ParameterizedType) {
064                                ParameterizedType superPt = (ParameterizedType) type;
065                                Type rawType = superPt.getRawType();
066                                if (rawType instanceof Class) {
067                                        Class<?> rawClass = (Class<?>) rawType;
068                                        if (rawClass.getName().endsWith(".BasePrimitive") || rawClass.getName().endsWith(".PrimitiveType")) {
069                                                Type typeVariable = superPt.getActualTypeArguments()[0];
070                                                if (typeVariable instanceof Class) {
071                                                        myNativeType = (Class<?>) typeVariable;
072                                                        break;
073                                                }
074                                        }
075                                }
076                        }
077                        clazz = clazz.getSuperclass();
078                }
079        }
080
081        @Override
082        public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() {
083                return ChildTypeEnum.PRIMITIVE_DATATYPE;
084        }
085
086        public Class<?> getNativeType() {
087                return myNativeType;
088        }
089
090        @Override
091        public Class<? extends IBaseDatatype> getProfileOf() {
092                return myProfileOfType;
093        }
094
095        @Override
096        public boolean isProfileOf(Class<? extends IBaseDatatype> theType) {
097                if (myProfileOfType != null) {
098                        if (myProfileOfType.equals(theType)) {
099                                return true;
100                        } else if (myProfileOf instanceof IRuntimeDatatypeDefinition) {
101                                return ((IRuntimeDatatypeDefinition) myProfileOf).isProfileOf(theType);
102                        }
103                }
104                return false;
105        }
106
107        @Override
108        public boolean isSpecialization() {
109                return mySpecialization;
110        }
111
112        @Override
113        void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) {
114                super.sealAndInitialize(theContext, theClassToElementDefinitions);
115
116                if (myProfileOfType != null) {
117                        myProfileOf = theClassToElementDefinitions.get(myProfileOfType);
118                        if (myProfileOf == null) {
119                                StringBuilder b = new StringBuilder();
120                                b.append("Unknown profileOf value: ");
121                                b.append(myProfileOfType);
122                                b.append(" in type ");
123                                b.append(getImplementingClass().getName());
124                                b.append(" - Valid types: ");
125                                b.append(theClassToElementDefinitions.keySet());
126                                throw new ConfigurationException(b.toString());
127                        }
128                }
129        }
130
131}