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.i18n.Msg; 023import ca.uhn.fhir.model.api.annotation.DatatypeDef; 024import ca.uhn.fhir.model.api.annotation.ResourceDef; 025import org.hl7.fhir.instance.model.api.IBase; 026import org.hl7.fhir.instance.model.api.IBaseDatatype; 027import org.hl7.fhir.instance.model.api.IPrimitiveType; 028 029import java.lang.reflect.ParameterizedType; 030import java.lang.reflect.Type; 031import java.util.ArrayList; 032import java.util.Collections; 033import java.util.List; 034import java.util.Map; 035 036import static org.apache.commons.lang3.StringUtils.isBlank; 037 038public class RuntimePrimitiveDatatypeDefinition extends BaseRuntimeElementDefinition<IPrimitiveType<?>> implements IRuntimeDatatypeDefinition { 039 040 private Class<?> myNativeType; 041 private BaseRuntimeElementDefinition<?> myProfileOf; 042 private Class<? extends IBaseDatatype> myProfileOfType; 043 private boolean mySpecialization; 044 private List<BaseRuntimeChildDefinition> myChildren; 045 private RuntimeChildExt myRuntimeChildExt; 046 047 public RuntimePrimitiveDatatypeDefinition(DatatypeDef theDef, Class<? extends IPrimitiveType<?>> theImplementingClass, boolean theStandardType) { 048 super(theDef.name(), theImplementingClass, theStandardType); 049 050 String resourceName = theDef.name(); 051 if (isBlank(resourceName)) { 052 throw new ConfigurationException(Msg.code(1689) + "Resource type @" + ResourceDef.class.getSimpleName() + " annotation contains no resource name: " + theImplementingClass.getCanonicalName()); 053 } 054 055 mySpecialization = theDef.isSpecialization(); 056 myProfileOfType = theDef.profileOf(); 057 if (myProfileOfType.equals(IBaseDatatype.class)) { 058 myProfileOfType = null; 059 } 060 061 determineNativeType(theImplementingClass); 062 } 063 064 @Override 065 public List<BaseRuntimeChildDefinition> getChildren() { 066 return myChildren; 067 } 068 069 @Override 070 public BaseRuntimeChildDefinition getChildByName(String theChildName) { 071 if ("extension".equals(theChildName)) { 072 return myRuntimeChildExt; 073 } 074 return null; 075 } 076 077 private void determineNativeType(Class<? extends IPrimitiveType<?>> theImplementingClass) { 078 Class<?> clazz = theImplementingClass; 079 while (clazz.equals(Object.class) == false) { 080 Type type = clazz.getGenericSuperclass(); 081 if (type instanceof ParameterizedType) { 082 ParameterizedType superPt = (ParameterizedType) type; 083 Type rawType = superPt.getRawType(); 084 if (rawType instanceof Class) { 085 Class<?> rawClass = (Class<?>) rawType; 086 if (rawClass.getName().endsWith(".BasePrimitive") || rawClass.getName().endsWith(".PrimitiveType")) { 087 Type typeVariable = superPt.getActualTypeArguments()[0]; 088 if (typeVariable instanceof Class) { 089 myNativeType = (Class<?>) typeVariable; 090 break; 091 } 092 } 093 } 094 } 095 clazz = clazz.getSuperclass(); 096 } 097 } 098 099 @Override 100 public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() { 101 return ChildTypeEnum.PRIMITIVE_DATATYPE; 102 } 103 104 public Class<?> getNativeType() { 105 return myNativeType; 106 } 107 108 @Override 109 public Class<? extends IBaseDatatype> getProfileOf() { 110 return myProfileOfType; 111 } 112 113 @Override 114 public boolean isProfileOf(Class<? extends IBaseDatatype> theType) { 115 if (myProfileOfType != null) { 116 if (myProfileOfType.equals(theType)) { 117 return true; 118 } else if (myProfileOf instanceof IRuntimeDatatypeDefinition) { 119 return ((IRuntimeDatatypeDefinition) myProfileOf).isProfileOf(theType); 120 } 121 } 122 return false; 123 } 124 125 @Override 126 public boolean isSpecialization() { 127 return mySpecialization; 128 } 129 130 @Override 131 void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) { 132 super.sealAndInitialize(theContext, theClassToElementDefinitions); 133 134 if (myProfileOfType != null) { 135 myProfileOf = theClassToElementDefinitions.get(myProfileOfType); 136 if (myProfileOf == null) { 137 StringBuilder b = new StringBuilder(); 138 b.append("Unknown profileOf value: "); 139 b.append(myProfileOfType); 140 b.append(" in type "); 141 b.append(getImplementingClass().getName()); 142 b.append(" - Valid types: "); 143 b.append(theClassToElementDefinitions.keySet()); 144 throw new ConfigurationException(Msg.code(1690) + b.toString()); 145 } 146 } 147 148 myRuntimeChildExt = new RuntimeChildExt(); 149 myRuntimeChildExt.sealAndInitialize(theContext, theClassToElementDefinitions); 150 151 myChildren = new ArrayList<>(); 152 myChildren.addAll(super.getChildren()); 153 myChildren.add(myRuntimeChildExt); 154 myChildren = Collections.unmodifiableList(myChildren); 155 } 156 157}